根据从下一行开始的当前值对行进行分组
Posted
技术标签:
【中文标题】根据从下一行开始的当前值对行进行分组【英文标题】:Group rows based on the current value starting from the next row 【发布时间】:2019-01-25 09:39:24 【问题描述】:我需要使用value <> z
增加所有下一行的组号。 z
意味着根据b
的所有下一行将具有相同的组号。
CREATE TABLE #tmp
(
a CHAR(1)
, b INT
);
INSERT INTO #tmp (a
, b)
VALUES ('a', 1)
, ('b', 2)
, ('z', 3)
, ('c', 4)
, ('z', 5)
, ('z', 6)
, ('d', 7);
SELECT t.a
, t.b
, SUM(v.is_z) OVER (ORDER BY t.b ROWS UNBOUNDED PRECEDING) - ROW_NUMBER() OVER (ORDER BY t.b) group_nbr
FROM #tmp AS t
CROSS APPLY (SELECT CASE WHEN a = 'z' THEN 2 ELSE 1 END AS is_z) AS v
ORDER BY 2;
DROP TABLE #tmp;
在我的查询中,组从值为z
的行开始递增,但我需要为下一行开始递增。
预期输出:
【问题讨论】:
'下一步'根据什么(b)? 是的。修改了问题。 【参考方案1】:一种解决方案是每次找到z
时加1,然后LAG 最后将结果加1。
;WITH CumulativeZ AS
(
SELECT
T.*,
CumulativeZ = SUM(CASE WHEN T.a = 'z' THEN 1 ELSE 0 END) OVER(ORDER BY T.b ASC)
FROM
#tmp AS T
)
SELECT
C.a,
C.b,
C.CumulativeZ,
[Group] = LAG(C.CumulativeZ, 1, 0) OVER (ORDER BY C.b ASC)
FROM
CumulativeZ AS C
结果:
a b CumulativeZ Group
a 1 0 0
b 2 0 0
z 3 1 0
c 4 1 1
z 5 2 1
z 6 3 2
d 7 3 3
请注意,LAG
函数适用于 SQL Server 2012+。您可以在 2008+ 版本上使用 ROW_NUMBER
模仿它的功能。
【讨论】:
【参考方案2】:您希望“z”s 标识组的结尾。您可以使用累积和分配组编号。我认为这是做你想做的最简单的方法。
如果您不关心数字的实际顺序,那么您可以这样做:
select t.*,
sum(case when a = 'z' then 1 else 0 end) over (order by b desc) as grp_desc
from #tmp t;
如果您希望组以“正确的方式”编号,您可以使用稍微复杂一点的表达式:
select t.*,
coalesce(sum(case when a = 'z' then 1 else 0 end) over
(order by b
rows between unbounded preceding and 1 preceding), 0
) as grp
from #tmp t;
Here 是一个 dbfiddle。
【讨论】:
估计的计划比接受的答案差大约两倍 @DmitrijKultasev 。 . .如果您的数据实际上有 7 行,那么没关系。对于任何规模很大的数据,交叉应用可能会变得很昂贵。 好的,你说服了我 :) 刚刚检查了真实数据(约 32M 行),它的性能好于所有提议的解决方案数倍。【参考方案3】:我会简单地使用apply
:
select t.a, t.b, tt.grp
from #tmp t outer apply
(select count(*) as grp
from #tmp t1
where t1.b < t.b and t1.a = 'z'
) tt;
【讨论】:
@DmitrijKultasev 。 . .这是一种非常低效的方式来做你想做的事。使用窗口函数通常要快得多,它们可以使用。以上是关于根据从下一行开始的当前值对行进行分组的主要内容,如果未能解决你的问题,请参考以下文章