选择我有一个表如下:在SQL Server 2005
ID | first | end
--------------------
a | 1 | 3
b | 3 | 8
c | 8 | 10
我想选择如下:
ID | first | end
---------------------
a-c | 1 | 10
但我不能这样做。请!帮我。谢谢!
选择我有一个表如下:在SQL Server 2005
ID | first | end
--------------------
a | 1 | 3
b | 3 | 8
c | 8 | 10
我想选择如下:
ID | first | end
---------------------
a-c | 1 | 10
但我不能这样做。请!帮我。谢谢!
这个工作对我来说:
SELECT MIN(t.id)+'-'+MAX(t.id) AS ID,
MIN(t.[first]) AS first,
MAX(t.[end]) AS [end]
FROM dbo.YOUR_TABLE t
但请,不要使用类似 “结束” 保留字列名。
我相信你可以做到这一点使用recursive Common Table Expression如下,特别是如果你不期望的记录很长的链条:
WITH Ancestors AS
(
SELECT
InitRow.[ID] AS [Ancestor],
InitRow.[ID],
InitRow.[first],
InitRow.[end],
0 AS [level],
'00000' + InitRow.[ID] AS [hacky_level_plus_ID]
FROM
YOUR_TABLE AS InitRow
WHERE
NOT EXISTS
(
SELECT * FROM YOUR_TABLE AS PrevRow
WHERE PrevRow.[end] = InitRow.[first]
)
UNION ALL
SELECT
ParentRow.Ancestor,
ChildRow.[ID],
ChildRow.[first],
ChildRow.[end],
ParentRow.level + 1 AS [level],
-- Avoids having to build the recursive structure more than once.
-- We know we will not be over 5 digits since CTEs have a recursion
-- limit of 32767.
RIGHT('00000' + CAST(ParentRow.level + 1 AS varchar(4)), 5)
+ ChildRow.[ID] AS [hacky_level_plus_ID]
FROM
Ancestors AS ParentRow
INNER JOIN YOUR_TABLE AS ChildRow
ON ChildRow.[first] = ParentRow.[end]
)
SELECT
Ancestors.Ancestor + '-' + SUBSTRING(MAX([hacky_level_plus_ID]),6,10) AS [IDs],
-- Without the [hacky_level_plus_ID] column, you need to do it this way:
-- Ancestors.Ancestor + '-' +
-- (SELECT TOP 1 Children.ID FROM Ancestors AS Children
-- WHERE Children.[Ancestor] = Ancestors.[Ancestor]
-- ORDER BY Children.[level] DESC) AS [IDs],
MIN(Ancestors.[first]) AS [first],
MAX(Ancestors.[end]) AS [end]
FROM
Ancestors
GROUP BY
Ancestors.Ancestor
-- If needed, add OPTION (MAXRECURSION 32767)
对各部分做一个快速的解释:
的WITH Ancestors AS (...)
子句创建名称为Ancestors
的公用表表达式(基本上是子查询)。该表达式中的第一个SELECT
建立了一个基线:在它之前没有匹配条目的所有行。
然后,第二SELECT
就是递归踢。因为它引用Ancestors
作为查询的一部分,它使用它已添加到表中的行,然后进行与新的从YOUR_TABLE
加入。这将递归地发现越来越多的行添加到每个链的末尾。
最后一项是SELECT
,它使用我们构建的这个递归表。它做了一个简单的GROUP BY
,因为我们保存了Ancestor
列中的原始ID,所以开始和结束是一个简单的MIN
和MAX
。
棘手的部分是找出链中最后一行的ID。有两种方法可以做到这一点,都在查询中说明。您可以使用递归表加入,在这种情况下,它将重新构建递归表,或者您可以尝试跟踪最后一个项目。 (如果构建链式记录的递归列表的代价很高,那么您肯定希望将您需要的次数降至最低。)
它跟踪它的方式是跟踪它在链中的位置(level
列 - 注意每次我们递归时我们如何加1),零填充它,然后将ID粘贴到最后。然后,获取具有最大level
的项目简单地是MAX
,接着剥离level
数据。
如果CTE必须递归太多,它会产生一个错误,但我相信你可以使用MAXRECURSION
选项来调整。默认值为100.如果您必须将其设置得高于此值,则可能需要考虑不使用递归CTE来执行此操作。
这也不能很好地处理格式错误的数据。如果您有两个记录具有相同的first
或记录first
== end
,那么这将无法正常工作,您可能需要调整CTE内部的连接条件或采用其他方法。
这不是唯一的方法。我相信如果您构建自定义过程并手动完成所有步骤,将会更容易。但是这具有以单一语句操作的优点。
非常感谢你。你回答简单吗?我只使用小型数据库。 – 2010-08-25 03:28:44
我明白了。但是我有一个表如下: ID第一端 b 3分配8 -C 8 10 d 15 19 E-10 12 F-19战斗机23 我认为它假。 因为我要选择 ID第一端 一个-E 3.0 12 d-F 15 23 – 2010-08-24 03:42:33
@Vuong:我认为,虽然,你可以扩展这一理念,以满足您的需求。如果您将计算列添加到您的选择中以生成分组标题(考虑使用'case'语句计算列),然后对计算进行分组,您仍然可以按照此处的建议应用“MIN”和“MAX”。 – kbrimington 2010-08-24 03:52:53
@Voung Mao:这是一个与你在问题中发布的数据集不同的数据集 - 如果这是你处理的内容,你应该发布这个问题的细节,因为任何人都必须阅读你的评论以了解其他标准。目前还不清楚你如何知道该数据集中有两个组,或者他们开始和结束的位置。 – 2010-08-24 04:03:13