【问题标题】:Tricky partition in SQLSQL中的棘手分区
【发布时间】:2020-07-13 03:45:48
【问题描述】:

我有一张这样的桌子

RID ID  DTE FLAG    AMT SUMAMT
1   1   2020-07-03 02:52:15.480 Y   10  NULL
2   1   2020-07-04 02:52:15.480 N   10  NULL
3   1   2020-07-05 02:52:15.480 N   10  NULL
4   1   2020-07-06 02:52:15.480 Y   10  NULL
5   1   2020-07-13 02:52:15.480 Y   10  NULL
6   2   2020-07-06 02:52:15.480 N   10  NULL
7   2   2020-07-13 02:52:15.480 Y   10  NULL

我需要这样的结果

RID ID  DTE FLAG    AMT SUMAMT
1   1   2020-07-03 02:52:15.480 Y   10  10
2   1   2020-07-04 02:52:15.480 N   10  NULL
3   1   2020-07-05 02:52:15.480 N   10  NULL
4   1   2020-07-06 02:52:15.480 Y   10  30
5   1   2020-07-13 02:52:15.480 Y   10  10
6   2   2020-07-06 02:52:15.480 N   10  NULL
7   2   2020-07-13 02:52:15.480 Y   10  20

我需要做的就是更新 'Y' FLAG 行项目的 SUMAMT 列。这里的条件是每当我们找到'Y' FLAG,我们需要检查过去是否有任何基于DTE的'N'标记的行项目,如果是我们需要对该行项目进行AMT并需要总结和更新SUMAMT。

SELECT RID,ID,DTE,FLAG,AMT,SUM(AMT) OVER (PARTITION BY ID ORDER BY ID,DTE) FROM #T

我尝试了上面的查询,它给出了运行总数,我不明白如何制作如下所述的分区......

RID ID  DTE FLAG    AMT SUMAMT
1   1   2020-07-03 02:52:15.480 Y   10  10

2   1   2020-07-04 02:52:15.480 N   10  NULL
3   1   2020-07-05 02:52:15.480 N   10  NULL
4   1   2020-07-06 02:52:15.480 Y   10  30

5   1   2020-07-13 02:52:15.480 Y   10  10

6   2   2020-07-06 02:52:15.480 N   10  NULL
7   2   2020-07-13 02:52:15.480 Y   10  20

查询创建表和插入数据...

CREATE TABLE #T
(
    RID INT IDENTITY(1, 1),
    ID INT,
    DTE DATETIME,
    FLAG VARCHAR(1),
    AMT INT,
    SUMAMT INT
)

INSERT INTO #T (ID, DTE, FLAG, AMT) 
VALUES (1, GETDATE() - 10, 'Y', 10),
       (1, GETDATE() - 9, 'N', 10),
       (1, GETDATE() - 8, 'N', 10),
       (1, GETDATE() - 7, 'Y', 10),
       (1, GETDATE(), 'Y', 10),
       (2, GETDATE() - 7, 'N', 10),
       (2, GETDATE(), 'Y', 10)

【问题讨论】:

    标签: sql sql-server window-functions azure-sql-server


    【解决方案1】:

    感谢您的示例数据。这很有帮助。

    在下面的查询中,我们将数据分成两部分:

    • 标记“Y”
    • 标记“N”

    现在,我们计算落在两个“Y”标志之间的标志“N”的所有行的总和。对于标志 'N' 行,没有计算。

    SELECT t.RID, t.id, t.dte,  t.amt,t.flag, isnull(t.amt+ot.sum_amt,amt)
    from 
    (SELECT 
    RID,ID, DTE, ISNULL(LAG(DTE,1) OVER(PARTITION BY ID ORDER BY DTE),'19000101') AS Prev_Yes
    , DTE as Current_Yes
    ,amt
    ,flag
    FROM #t as cr WHERE Flag = 'Y') as t
    OUTER APPLY
    (SELECT SUM(AMT) FROM #t
    WHERE flag = 'N' 
    AND DTE > t.Prev_Yes AND DTE < t.Current_Yes
    and ID = t.id) as ot(sum_amt) 
    UNION ALL
    SELECT RID, id, dte,  amt,flag, NULL AS SUM_AMT
    FROM #t 
    WHERE flag = 'N'
    ORDER BY rid
    
    
    +-----+----+-------------------------+-----+------+------------------+
    | RID | id |           dte           | amt | flag | (No column name) |
    +-----+----+-------------------------+-----+------+------------------+
    |   1 |  1 | 2020-07-03 09:35:10.513 |  10 | Y    | 10               |
    |   2 |  1 | 2020-07-04 09:35:10.513 |  10 | N    | NULL             |
    |   3 |  1 | 2020-07-05 09:35:10.513 |  10 | N    | NULL             |
    |   4 |  1 | 2020-07-06 09:35:10.513 |  10 | Y    | 30               |
    |   5 |  1 | 2020-07-13 09:35:10.513 |  10 | Y    | 10               |
    |   6 |  2 | 2020-07-06 09:35:10.513 |  10 | N    | NULL             |
    |   7 |  2 | 2020-07-13 09:35:10.513 |  10 | Y    | 20               |
    +-----+----+-------------------------+-----+------+------------------+
    
    
    

    【讨论】:

    • RID 4 的值应为 30,因为过去有两个 N 行项目为 10 + 10,一个 Y 行项目为 10,因此总共应为 30。RID 的条件相同7 以及值应该是 20
    • @James,知道了。我现在修改了查询和结果集
    猜你喜欢
    • 1970-01-01
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-12
    • 1970-01-01
    • 2022-01-06
    相关资源
    最近更新 更多