SQL 服务器:使用带有序集的 Windows 函数
SQL Server: Use of Windows Function with ordered set
使用此示例数据集:
ID POS 数量 A B
32 1 50 1 2
28 2 200 1 2
12 3 300 2 2
16 4 400 1 2
98 5 500 3 1
56 6 600 2 2
33 7 700 2 2
如何按组获取 SUM(QTY)。组基于不同的 (A 和 B) 按 POS 排序!!!
作为:
ID POS QTY A B SUM(QTY)
32 1 50 1 2 250 第一组
28 2 200 1 2 250 第 1 组
12 3 300 2 2 300 第 2 组
16 4 400 1 2 900 第 3 组而非 1
98 5 500 1 2 900 第 3 组而非第 1 组
56 6 600 2 2 1300 第 4 组而非第 2 组
33 7 700 2 2 1300 第 4 组而非第 2 组
我尝试过使用 PARTITION BY 的不同解决方案,但总是得到具有相同 A 和 B 总和的组。
POS 顺序很重要,因为相同的 A 和 B 形成不同的组。
select t1.*, t2.sum_qty
from your_table t1
join
(
select a, b, sum(qty) as sum_qty
from your_table
group by a, b
) t2 on t1.a = t2.a and t1.b = t2.b
order by t1.pos
一定有更漂亮的方法来做到这一点,但这是我现在得到的:
declare @t table (ID int,POS int,QTY int,A int,B int)
insert into @t(ID,POS,QTY,A,B) values
(32,1, 50,1,2), (28,2,200,1,2), (12,3,300,2,2), (16,4,400,1,2),
(98,5,500,1,2), (56,6,600,2,2), (33,7,700,2,2)
;With Origins as (
select t1.*
from @t t1
left join
@t t2
on
t1.POS = t2.POS + 1 and
t1.A = t2.A and
t1.B = t2.B
where t2.POS is null
)
select
t.*,SUM(t.QTY) OVER (PARTITION BY o.POS) as Qty
from
@t t
inner join
Origins o
on
t.A = o.A and
t.B = o.B and
t.POS >= o.POS
left join
Origins o_other
on
t.A = o_other.A and
t.B = o_other.B and
t.POS >= o_other.POS and
o_other.POS > o.POS
where
o_other.POS is null
其中 Origins CTE 用于查找每个 "partition" 的第一行。这假设 POS
没有间隙 - 但如果有,则可以使用基于 POS
使用 ROW_NUMBER()
的另一个 CTE 代替它。
最后的查询然后通过找到最近的具有较低 POS
值的行将每一行连接到 "correct" Origins
行,然后我们将其用作键分区。
结果:
ID POS QTY A B Qty
----------- ----------- ----------- ----------- ----------- -----------
32 1 50 1 2 250
28 2 200 1 2 250
12 3 300 2 2 300
16 4 400 1 2 900
98 5 500 1 2 900
56 6 600 2 2 1300
33 7 700 2 2 1300
(我更改了示例数据以匹配您的预期结果,而不是您问题顶部显示的内容,其中有一个 3,1
行用于条目 5
)。
使用此示例数据集:
ID POS 数量 A B 32 1 50 1 2 28 2 200 1 2 12 3 300 2 2 16 4 400 1 2 98 5 500 3 1 56 6 600 2 2 33 7 700 2 2
如何按组获取 SUM(QTY)。组基于不同的 (A 和 B) 按 POS 排序!!!
作为:
ID POS QTY A B SUM(QTY) 32 1 50 1 2 250 第一组 28 2 200 1 2 250 第 1 组 12 3 300 2 2 300 第 2 组 16 4 400 1 2 900 第 3 组而非 1 98 5 500 1 2 900 第 3 组而非第 1 组 56 6 600 2 2 1300 第 4 组而非第 2 组 33 7 700 2 2 1300 第 4 组而非第 2 组
我尝试过使用 PARTITION BY 的不同解决方案,但总是得到具有相同 A 和 B 总和的组。
POS 顺序很重要,因为相同的 A 和 B 形成不同的组。
select t1.*, t2.sum_qty
from your_table t1
join
(
select a, b, sum(qty) as sum_qty
from your_table
group by a, b
) t2 on t1.a = t2.a and t1.b = t2.b
order by t1.pos
一定有更漂亮的方法来做到这一点,但这是我现在得到的:
declare @t table (ID int,POS int,QTY int,A int,B int)
insert into @t(ID,POS,QTY,A,B) values
(32,1, 50,1,2), (28,2,200,1,2), (12,3,300,2,2), (16,4,400,1,2),
(98,5,500,1,2), (56,6,600,2,2), (33,7,700,2,2)
;With Origins as (
select t1.*
from @t t1
left join
@t t2
on
t1.POS = t2.POS + 1 and
t1.A = t2.A and
t1.B = t2.B
where t2.POS is null
)
select
t.*,SUM(t.QTY) OVER (PARTITION BY o.POS) as Qty
from
@t t
inner join
Origins o
on
t.A = o.A and
t.B = o.B and
t.POS >= o.POS
left join
Origins o_other
on
t.A = o_other.A and
t.B = o_other.B and
t.POS >= o_other.POS and
o_other.POS > o.POS
where
o_other.POS is null
其中 Origins CTE 用于查找每个 "partition" 的第一行。这假设 POS
没有间隙 - 但如果有,则可以使用基于 POS
使用 ROW_NUMBER()
的另一个 CTE 代替它。
最后的查询然后通过找到最近的具有较低 POS
值的行将每一行连接到 "correct" Origins
行,然后我们将其用作键分区。
结果:
ID POS QTY A B Qty
----------- ----------- ----------- ----------- ----------- -----------
32 1 50 1 2 250
28 2 200 1 2 250
12 3 300 2 2 300
16 4 400 1 2 900
98 5 500 1 2 900
56 6 600 2 2 1300
33 7 700 2 2 1300
(我更改了示例数据以匹配您的预期结果,而不是您问题顶部显示的内容,其中有一个 3,1
行用于条目 5
)。