TSQL 按具有多个值的列分组
TSQL Group by Column with Multiple Values
我在 SQLServer 2008r2 中有一个 table,如下所示。
我想 select [Fg]
列 = 1 的所有记录,按 [Id]
顺序连续为每个 [T_Id]
和 [N_Id]
组合。
可能存在 [Fg]
= 2 之前的记录不 = 1
的情况
[Fg]
= 1 的记录可以有任意数量,但每个 [T_Id]
和 [N_Id]
组合只有一个 [Fg]
= 2 的记录。
所以对于下面的例子,我想 select 记录 [Id]
s (4,5) and (7,8,9 )and (19,20).
[T_Id]
3 和 4 的任何记录都被排除。
预期输出
示例数据集
DECLARE @Data TABLE ( Id INT IDENTITY (1,1), T_Id INT, N_Id INT, Fg TINYINT )
INSERT INTO @Data
(T_Id, N_Id, Fg)
VALUES
(1, 2, 0), (1, 2, 1), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 3, 0), (2, 3, 1),
(2, 3, 1), (2, 3, 2), (3, 4, 0), (3, 4, 0), (3, 4, 0), (3, 4, 2), (4, 5, 0),
(4, 5, 1), (4, 5, 0), (4, 5, 2), (5, 7, 0), (5, 7, 1), (5, 7, 2)
使用recursive CTE
可以轻松完成:
WITH DataSource AS
(
SELECT DS1.*
FROM @Data DS1
INNER JOIN @Data DS2
ON DS1.[T_Id] = DS2.[T_Id]
AND DS1.[N_Id] = DS2.[N_Id]
AND DS1.[Id] = DS2.[Id] + 1
AND DS1.[Fg] = 2
AND DS2.[Fg] = 1
UNION ALL
SELECT DS1.*
FROM @Data DS1
INNER JOIN DataSource DS2
ON DS1.[T_Id] = DS2.[T_Id]
AND DS1.[N_Id] = DS2.[N_Id]
AND DS1.[Id] = DS2.[Id] - 1
AND DS1.[Fg] = 1
)
SELECT *
FROM DataSource
ORDER BY Id
这个想法很简单。查询的第一部分获取所有 valid
条带 fg = 2
的记录 - 有效意味着在此之前有来自同一组的带 fg = 1
的记录。
然后在递归部分,我们得到的所有记录都小于初始记录,即fg = 1
。
您不能使用 lag/lead,因为它开始于 SQL 2012 年,您将需要执行如下操作。
SELECT fg - (
SELECT TOP 1 fg
FROM table m2
WHERE m2.fg = m1.fg-1 OR (m2.fg = m1.fg AND m2.id < m1.id)
ORDER BY
fg, id
)
FROM table m1
ORDER BY
fg, id
我在 SQLServer 2008r2 中有一个 table,如下所示。
我想 select [Fg]
列 = 1 的所有记录,按 [Id]
顺序连续为每个 [T_Id]
和 [N_Id]
组合。
可能存在 [Fg]
= 2 之前的记录不 = 1
[Fg]
= 1 的记录可以有任意数量,但每个 [T_Id]
和 [N_Id]
组合只有一个 [Fg]
= 2 的记录。
所以对于下面的例子,我想 select 记录 [Id]
s (4,5) and (7,8,9 )and (19,20).
[T_Id]
3 和 4 的任何记录都被排除。
预期输出
示例数据集
DECLARE @Data TABLE ( Id INT IDENTITY (1,1), T_Id INT, N_Id INT, Fg TINYINT )
INSERT INTO @Data
(T_Id, N_Id, Fg)
VALUES
(1, 2, 0), (1, 2, 1), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 3, 0), (2, 3, 1),
(2, 3, 1), (2, 3, 2), (3, 4, 0), (3, 4, 0), (3, 4, 0), (3, 4, 2), (4, 5, 0),
(4, 5, 1), (4, 5, 0), (4, 5, 2), (5, 7, 0), (5, 7, 1), (5, 7, 2)
使用recursive CTE
可以轻松完成:
WITH DataSource AS
(
SELECT DS1.*
FROM @Data DS1
INNER JOIN @Data DS2
ON DS1.[T_Id] = DS2.[T_Id]
AND DS1.[N_Id] = DS2.[N_Id]
AND DS1.[Id] = DS2.[Id] + 1
AND DS1.[Fg] = 2
AND DS2.[Fg] = 1
UNION ALL
SELECT DS1.*
FROM @Data DS1
INNER JOIN DataSource DS2
ON DS1.[T_Id] = DS2.[T_Id]
AND DS1.[N_Id] = DS2.[N_Id]
AND DS1.[Id] = DS2.[Id] - 1
AND DS1.[Fg] = 1
)
SELECT *
FROM DataSource
ORDER BY Id
这个想法很简单。查询的第一部分获取所有 valid
条带 fg = 2
的记录 - 有效意味着在此之前有来自同一组的带 fg = 1
的记录。
然后在递归部分,我们得到的所有记录都小于初始记录,即fg = 1
。
您不能使用 lag/lead,因为它开始于 SQL 2012 年,您将需要执行如下操作。
SELECT fg - (
SELECT TOP 1 fg
FROM table m2
WHERE m2.fg = m1.fg-1 OR (m2.fg = m1.fg AND m2.id < m1.id)
ORDER BY
fg, id
)
FROM table m1
ORDER BY
fg, id