【问题标题】:T-SQL - Get last as-at date SUM(Quantity) was not negativeT-SQL - 获取最后一个截止日期 SUM(Quantity) 不是负数
【发布时间】:2017-02-06 00:56:20
【问题描述】:

我正在尝试找到一种按位置获取最后日期的方法,并且产品总和为正。我能想到的唯一方法是使用光标,如果是这种情况,我不妨在代码中进行。在我走那条路之前,我希望有人可能有更好的主意?

表: 产品、日期、地点、数量

场景是;我在特定日期按位置和产品查找数量,如果它是负数,我需要获得该组最后一次正数的总和和日期。

select 
    Product, 
    Location, 
    SUM(Quantity) Qty,
    SUM(Value) Value
from 
    ProductTransactions PT  
where
    Date <= @AsAtDate
group by 
    Product, 
    Location

【问题讨论】:

  • 您还按产品和位置分组。您想要每个组或整个表格的最后一个肯定日期吗?
  • @TimBiegeleisen 对于小组,我更新了问题以反映这一点。谢谢。

标签: sql-server tsql aggregate-functions


【解决方案1】:

我正在寻找之前交易总和为正数的最后日期

根据您修改后的问题和您的评论,我希望这里有另一个解决方案可以回答您的问题。

select Product, Location, max(Date) as Date
from (
    select a.Product, a.Location, a.Date from ProductTransactions as a
    join ProductTransactions as b
    on a.Product = b.Product and a.Location = b.Location
    where b.Date <= a.Date
    group by a.Product, a.Location, a.Date
    having sum(b.Value) >= 0
) as T
group by Product, Location

子查询(表 T)生成 {product, location, date} 行的列表,其中先前(包括)值的总和为正。从该集合中,我们选择每个 {product, location} 对的最后日期。

【讨论】:

  • 抱歉,我不应该在我的组中设置日期,我希望总和是“原样”,而不仅仅是该日期的交易。
【解决方案2】:

这可以使用窗口聚合以基于集合的方式完成,以构建运行总计。根据表中的行数,这可能会有点慢,但您不能真正限制向后追溯的时间范围,因为最后一个正日期是未知数量。

为方便起见,我使用 CTE 来构建聚合数据集,但将其转换为临时表应该更快。 (每次调用 CTE 时都会执行一次,而临时表只会执行一次。)

基本理论是使用OVER 子句对SUM 聚合进行分区和排序,从而构建所有前几天的运行总计。然后使用该数据集并将其过滤到预期日期。当该表中的一行的数量小于零时,它将重新连接到该产品和数量大于零的位置的所有前几天的聚合数据集。

由于这可能会返回多个正日期行,因此ROW_NUMBER() 函数用于根据正数日期的日期对行进行排序。这是按降序完成的,因此第 1 行是最近的正数日。此处无法使用简单的MIN(),因为MIN([Date]) 可能与MIN(Quantity) 不对应。

WITH x AS (
    SELECT [Date],
        Product,
        [Location],
        SUM(Quantity) OVER (PARTITION BY Product, [Location] ORDER BY [Date] ASC) AS Quantity,
        SUM([Value]) OVER(PARTITION BY Product, [Location] ORDER BY [Date] ASC) AS [Value]
    FROM ProductTransactions
    WHERE [Date] <= @AsAtDate
)
SELECT [Date], Product, [Location], Quantity, [Value], Positive_date, Positive_date_quantity
FROM (
    SELECT x1.[Date], x1.Product, x1.[Location], x1.Quantity, x1.[Value],
        x2.[Date] AS Positive_date, x2.[Quantity] AS Positive_date_quantity,
        ROW_NUMBER() OVER (PARTITION BY x1.Product, x1.[Location] ORDER BY x2.[Date] DESC) AS Positive_date_row
    FROM x AS x1
    LEFT JOIN x AS x2 ON x1.Product=x2.Product AND x1.[Location]=x2.[Location]
        AND x2.[Date]<x1.[Date] AND x1.Quantity<0 AND x2.Quantity>0
    WHERE x1.[Date] = @AsAtDate
) AS y
WHERE Positive_date_row=1

【讨论】:

    【解决方案3】:

    你的意思是要让组中正数的最后日期变为正数吗?

    例如,如果您使用的是 SQL Server 2012+: 在以下场景中,当日期为 2017 年 1 月 3 日时,数量汇总为 1(-10+5+6)。 下一个日期的数量有可能再次变成负数吗?

    ;WITH tb(Product, Location,[Date],Quantity) AS(
         SELECT 'A','B',CONVERT(DATETIME,'01/01/2017'),-10 UNION ALL 
         SELECT 'A','B','01/02/2017',5 UNION ALL 
         SELECT 'A','B','01/03/2017',6 UNION ALL 
         SELECT 'A','B','01/04/2017',2
    )
    SELECT  t.Product,t.Location,SUM(t.Quantity) AS Qty,MIN(CASE WHEN t.CurrentSum>0 THEN t.Date ELSE NULL END ) AS LastPositiveDate
    FROM (
        SELECT *,SUM(tb.Quantity)OVER(ORDER BY [Date]) AS CurrentSum FROM tb
    ) AS t GROUP BY t.Product,t.Location
    
    产品位置 数量 LastPositiveDate -------- -------- ----------- ----------- A B 3 2017-01-03 00:00:00.000

    【讨论】:

    • 嗨,不,我正在寻找之前交易总和包括它为正数的最后日期。谢谢。
    • @TheRealTy 你想获得数量总和变为正数的最后日期吗?顺便说一句,您使用的是什么版本的 SQL Server
    • 您可以将语句中的 MIN 替换为 MAX,这将返回该日期之前的交易总和为正数时的最新日期。
    猜你喜欢
    • 2012-04-07
    • 1970-01-01
    • 2014-12-14
    • 2018-04-09
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    相关资源
    最近更新 更多