T-SQL 不要忽略 SUM 中的 NULL 值

T-SQL Do not ignore NULL values in SUM

我正在尝试将 运行 总计添加到 table,在 NULL 值上,运行 总计应该为 NULL。但是 SUM 忽略 NULL 值。

有没有办法不忽略 SUM 中的 NULL?

SELECT
    run_key,
    time_empty,
    SUM(time_empty) OVER (PARTITION BY col1, col2 ORDER BY run_key ROWS BETWEEN UNBOUNDED PRECEDING  AND CURRENT ROW) as time_empty_rt
FROM 
    tblmytable
ORDER BY 
    run_key

我看不出除了分两步来解决这个问题,首先是 gaps and islands problem 确定要总结的岛屿,然后再进行总结。首先是岛屿:

DECLARE @T TABLE (run_key INT, time_empty INT, Col1 INT, Col2 INT)
INSERT @T (run_key, time_empty) 
VALUES
    (1, 637), (2, NULL), (3, NULL), (4, NULL), 
    (5, 2967), (6, 1000), (7, NULL), (8, NULL);

SELECT  run_key,
        time_empty, 
        IslandID = ROW_NUMBER() OVER(ORDER BY Run_key) - 
                    ROW_NUMBER() 
                                OVER(PARTITION BY 
                                        Col1, 
                                        Col2, 
                                        CASE WHEN time_empty IS NULL THEN 1 ELSE 0 END 
                                    ORDER BY Run_key)
FROM    @T
ORDER BY run_key;

给出:

run_key time_empty  IslandID
------------------------------
1       637         0
2       NULL        1
3       NULL        1
4       NULL        1
5       2967        3
6       1000        3
7       NULL        3
8       NULL        3

这现在为您提供了一个要分区的列 (IslandID),它将在下一个非空时正确地重置您的总和:

DECLARE @T TABLE (run_key INT, time_empty INT, Col1 INT, Col2 INT)
INSERT @T (run_key, time_empty) 
VALUES
    (1, 637), (2, NULL), (3, NULL), (4, NULL), 
    (5, 2967), (6, 1000), (7, NULL), (8, NULL);

SELECT  run_key,
        time_empty,
        time_empty_rt = CASE WHEN time_empty IS NULL THEN NULL
                            ELSE SUM(time_empty) 
                                    OVER (PARTITION BY Col1, Col2, IslandID
                                            ORDER BY run_key 
                                            ROWS BETWEEN UNBOUNDED PRECEDING  AND CURRENT ROW)
                        END
FROM    (   SELECT  run_key,
                    time_empty, 
                    Col1,
                    Col2,
                    IslandID = ROW_NUMBER() OVER(ORDER BY Run_key)
                                 - ROW_NUMBER() 
                                            OVER(PARTITION BY 
                                                    Col1, 
                                                    Col2, 
                                                    CASE WHEN time_empty IS NULL THEN 1 ELSE 0 END 
                                                ORDER BY Run_key)
            FROM    @T
        ) AS t;

您可以为具有相同数量的前面 null 列的每个组创建一个分区。

select  run_key
,       time_empty
,       sum(time_empty) over (
            partition by preceding_nulls
            order by run_key 
            rows between unbounded preceding and current row) as time_emtpy_rt
from    (
        select  sum(case when time_empty is null then 1 else 0 end) over (
                    order by run_key 
                    rows between unbounded preceding and current row) as preceding_nulls
        ,       *
        from    YourTable yt
        ) sub

Example at SQL Fiddle.