SQL Server:使用有序集的 Windows 函数

Posted

技术标签:

【中文标题】SQL Server:使用有序集的 Windows 函数【英文标题】:SQL Server: Use of Windows Function with ordered set 【发布时间】:2015-03-19 11:12:06 【问题描述】:

使用此示例数据集:

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)ORDERED BY POS !!!

作为:

ID POS QTY A B SUM(QTY) 32 1 50 1 2 250 第 1 组 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 形成不同的组。

【问题讨论】:

按 (A+B) 分组不起作用,因为组合 2+2 = 1+3 = 3+1 等。如果您知道 B 的范围(例如 B 总是 【参考方案1】:

必须有更漂亮的方法来做到这一点,但这是我现在所拥有的:

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 用于查找每个“分区”的第一行。这假设 POS 没有间隙 - 但如果确实如此,则可以使用基于 POS 的另一个使用 ROW_NUMBER() 的 CTE。

最后的查询然后通过找到最近的具有较低 POS 值的行将每一行连接到“正确的”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)。

【讨论】:

由于 POS 值有差距,您如何使用 ROW_NUMBER() 代替 POS 来表示 Origins CTE? @P.A - 只需在顶部添加一个新的 CTE With NewT as (select *,ROW_NUMBER() OVER (ORDER by POS) as NewPOS from @t),然后在查询中当前存在 @tPOS 的任何位置使用 NewTNewPOS 谢谢,完成了,使用带有 row_number() 的临时表,就像您使用这个新的 CTE。【参考方案2】:
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

【讨论】:

不起作用,sum(qty) 为所有具有相同 A 和 B 的行返回 sum()

以上是关于SQL Server:使用有序集的 Windows 函数的主要内容,如果未能解决你的问题,请参考以下文章

具有大型数据集的 SQL Server 中的数据透视表

Microsoft SQL Server 2016,T-SQL:根据各个日期获取数据集的日期范围

SQL Server 中对大型数据集的慢速不同查询

sql server中取交集差集和并集的语法

使用临时表时,描述第一个结果集的SQL Server失败(sp_describe_first_result_set)

从 sql server 迁移到大型数据集的 sqlite 的最快方法