TSQL - 困难的分组
TSQL - Difficult Grouping
请参阅fiddle:http://sqlfiddle.com/#!6/e6768/2
我有数据,如下:
DRIVER DROP
1 1
1 2
1 ReturnToBase
1 4
1 5
1 ReturnToBase
1 6
1 7
2 1
2 2
2 ReturnToBase
2 4
我正在尝试对我的数据进行分组,因此对于每个车手,每组 return 到基地都有一个分组编号。
我的输出应该是这样的:
DRIVER DROP GROUP
1 1 1
1 2 1
1 ReturnToBase 1
1 4 2
1 5 2
1 ReturnToBase 2
1 6 3
1 7 3
1 ReturnToBase 3
2 1 1
2 2 1
2 ReturnToBase 1
2 4 2
我试过结合窗口函数得到这个结果,但到目前为止我还差得远
以下是我目前所拥有的,它不应该起作用我试图弄清楚它是如何完成的,如果可能的话。
SELECT
ROW_NUMBER() OVER (Partition BY Driver order by Driver Desc) rownum,
Count(1) OVER (Partition By Driver Order By Driver Desc) counter,
Count
DropNo,
Driver,
CASE DropNo
WHEN 'ReturnToBase' THEN 1 ELSE 0 END AS EnumerateRound
FROM
Rounds
您可以使用以下查询:
SELECT id, DRIVER, DROPno,
1 + SUM(flag) OVER (PARTITION BY DRIVER ORDER BY id) -
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS grp
FROM (
SELECT id, DRIVER, DROPno,
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS flag
FROM rounds ) AS t
此查询使用 SUM
的窗口版本和 OVER
子句中的 ORDER BY
来计算 运行 总数。此版本的 SUM
可从 SQL Server 2012 AFAIK 开始使用。
为了获得正确的 GROUP
值,我们只需要稍微调整这个 运行 总值。
编辑:(归功于@Conrad Frix)
使用 CROSS APPLY
而不是内联视图可以大大简化事情:
SELECT id, DRIVER, DROPno,
1 + SUM(x.flag) OVER (PARTITION BY DRIVER ORDER BY id) - x.flag
FROM rounds
CROSS APPLY (SELECT CASE WHEN DROPno = 'ReturnToBase' THEN 1 ELSE 0 END) AS x(flag)
在您的示例中添加了顺序 ID 列以用于递归 CTE:
with cte as (
select ID,DRIVER,DROPno,1 as GRP
FROM rounds
where ID = 1
union all
select a.ID
,a.DRIVER
,a.DROPno
,case when b.DROPno = 'ReturnToBase'
or b.DRIVER <> a.DRIVER then b.GRP + 1
else b.GRP end
from rounds a
inner join cte b
on a.ID = b.ID + 1
)
select * from cte
请参阅fiddle:http://sqlfiddle.com/#!6/e6768/2
我有数据,如下:
DRIVER DROP
1 1
1 2
1 ReturnToBase
1 4
1 5
1 ReturnToBase
1 6
1 7
2 1
2 2
2 ReturnToBase
2 4
我正在尝试对我的数据进行分组,因此对于每个车手,每组 return 到基地都有一个分组编号。
我的输出应该是这样的:
DRIVER DROP GROUP
1 1 1
1 2 1
1 ReturnToBase 1
1 4 2
1 5 2
1 ReturnToBase 2
1 6 3
1 7 3
1 ReturnToBase 3
2 1 1
2 2 1
2 ReturnToBase 1
2 4 2
我试过结合窗口函数得到这个结果,但到目前为止我还差得远
以下是我目前所拥有的,它不应该起作用我试图弄清楚它是如何完成的,如果可能的话。
SELECT
ROW_NUMBER() OVER (Partition BY Driver order by Driver Desc) rownum,
Count(1) OVER (Partition By Driver Order By Driver Desc) counter,
Count
DropNo,
Driver,
CASE DropNo
WHEN 'ReturnToBase' THEN 1 ELSE 0 END AS EnumerateRound
FROM
Rounds
您可以使用以下查询:
SELECT id, DRIVER, DROPno,
1 + SUM(flag) OVER (PARTITION BY DRIVER ORDER BY id) -
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS grp
FROM (
SELECT id, DRIVER, DROPno,
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS flag
FROM rounds ) AS t
此查询使用 SUM
的窗口版本和 OVER
子句中的 ORDER BY
来计算 运行 总数。此版本的 SUM
可从 SQL Server 2012 AFAIK 开始使用。
为了获得正确的 GROUP
值,我们只需要稍微调整这个 运行 总值。
编辑:(归功于@Conrad Frix)
使用 CROSS APPLY
而不是内联视图可以大大简化事情:
SELECT id, DRIVER, DROPno,
1 + SUM(x.flag) OVER (PARTITION BY DRIVER ORDER BY id) - x.flag
FROM rounds
CROSS APPLY (SELECT CASE WHEN DROPno = 'ReturnToBase' THEN 1 ELSE 0 END) AS x(flag)
在您的示例中添加了顺序 ID 列以用于递归 CTE:
with cte as (
select ID,DRIVER,DROPno,1 as GRP
FROM rounds
where ID = 1
union all
select a.ID
,a.DRIVER
,a.DROPno
,case when b.DROPno = 'ReturnToBase'
or b.DRIVER <> a.DRIVER then b.GRP + 1
else b.GRP end
from rounds a
inner join cte b
on a.ID = b.ID + 1
)
select * from cte