SQL 聚合总和以仅清除负行

Posted

技术标签:

【中文标题】SQL 聚合总和以仅清除负行【英文标题】:SQL Aggregate Sum to Only Net Out Negative Rows 【发布时间】:2016-04-23 00:53:42 【问题描述】:

我正在尝试根据日期汇总产品价值。下面的示例从 20,000 开始,加上 5,000,然后减去 7,000。结果应该是吃完整个 5,000,然后进入前面的正数行。这将删除 5,000 行。

我认为这就像执行按日期降序排序的求和窗口函数一样简单。但是,正如您在下面看到的,我想在任何仍然为正的行处停止求和,然后移至下一行。

我无法弄清楚 SQL 中的逻辑来完成这项工作。在我的脑海里,应该是:

SUM(Value) OVER (PARTITION BY Product, (positive valued rows) ORDER BY Date DESC)

但是一行中可能有多个正值行,其中一个负值行可能会吞噬所有行,或者一行中可能有多个负值。

This post 似乎很有希望,但我认为如果负值大于正值,该逻辑将不起作用。

有:

+------------+----------------+-------+
|    Date    |    Product     | Value |
+------------+----------------+-------+
| 01/13/2015 | Prod1          | 20000 |
| 08/13/2015 | Prod1Addition1 |  5000 |
| 12/13/2015 | Prod1Removal   | -7000 |
| 02/13/2016 | Prod1Addition2 |  2000 |
| 03/13/2016 | Prod1Addition3 |  1000 |
| 04/13/2016 | Prod1Removal   | -1500 |
+------------+----------------+-------+

想要:

+------------+----------------+-------+
|    Date    |    Product     | Value |
+------------+----------------+-------+
| 01/13/2015 | Prod1          | 18000 |
| 02/13/2016 | Prod1Addition2 |  1500 |
+------------+----------------+-------+

【问题讨论】:

【参考方案1】:

我只能想到递归cte解决方案

; with 
cte as
(
    select  Date, Product, Value, rn = row_number() over (order by Date)
    from    yourtable
),
rcte as
(
    select  Date, Product, Value, rn, grp = 1
    from    cte 
    where   rn  = 1
    union all
    select  Date    = case when r.Value < 0 then c.Date else r.Date end, 
        Product = case when r.Value < 0 then c.Product else r.Product end, 
        c.Value, 
        c.rn, 
        grp = case when r.Value < 0 then r.grp + 1 else r.grp end
    from    rcte r
        inner join cte c    on  r.rn    = c.rn - 1
)
select  Date, Product, Value = sum(Value)
from    rcte
group by Date, Product, grp     
order by Date

【讨论】:

由于性能问题,我害怕递归 CTE。在查询数据之前,这会是在 ETL 流程中要做的事情吗? 不管性能问题,这值得我投一票。对于 OP,如果您想要更好的性能,您可以尝试使用一些带有 CURSOR 的解决方案。我敢肯定你没有很多选择来解决这个问题,这是一个棘手的问题。一种可能的解决方案(简单且性能最佳)是尝试使用一些 .NET 自定义函数,在一些 .NET 程序集中创建该函数,在查询中使用它。 .NET 函数允许您使用一些静态变量,因此您可以轻松定义它以返回分组的键。 @KingKing 您是否有任何指向文档和示例的链接可以向我展示您所指的内容?我同意松鼠的回答与问题非常相关。 @houstonwp 你可以仔细阅读这个页面(那里有一个注释部分和一个 CLR 用户定义函数的简单示例)msdn.microsoft.com/en-us/library/… 关于返回分组键,该函数应该只收到 1参数(通过Value 传入),您需要在函数外部的 C# 代码中声明一个静态变量。在函数中,您只需检查传入的参数,如果它小于0,则在返回该静态变量后将静态变量加 1。【参考方案2】:

我认为你想要这个:

select Date,
       Product,
       Sum(Value) As Value
  From TABLE_NAME
 Group By Date, Product
 Order by Date, Product;

对吗?

【讨论】:

不,这是按日期分组,每次添加和删除的日期都不同。

以上是关于SQL 聚合总和以仅清除负行的主要内容,如果未能解决你的问题,请参考以下文章

在 Apache Druid 中使用 SQL 将聚合函数应用于某些列

Yarn聚合日志, 过期清除配置不生效

如何仅清除qyqt5中的图?

SQL 聚合总和产生意外输出

使用多个 WHERE 子句和 GROUP BY 销售人员访问 SQL、聚合总和

SQL Server 快速清除日志文件的方法