簡體   English   中英

列定義范圍內的總和

[英]Sum in range defined by column

我有一張桌子是這樣的:

數量 地位 時間戳
10 一種 0
10 1個
15 2個
10 C 3個
12 4個
20 一種 5個
25 6個
17 C 7
19 8個

金額沒有限制(除了是一個數字)。 並且狀態行可以重復(示例中的“B”)。

我想要的是總結“A”狀態之間的所有內容。 所以結果應該是

時間戳
57 1個
81 5個

我需要這個用於 ansi-sql (Spark)

另一個解決方案:

with data(ts, amount, status) as (
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF'), 10, 'A' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+1/24, 10, 'B' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+2/24, 15, 'B' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+3/24, 10, 'C' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+4/24, 12, 'D' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+5/24, 20, 'A' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+6/24, 25, 'B' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+7/24, 17, 'C' from dual union all
    select to_timestamp('27-11-2022 12:00:00.00', 'DD-MM-YYYY HH24:MI:SS.FF')+8/24, 19, 'D' from dual 
)
select res from (
    select 
        status, ts, sum(amount) over(partition by s) as res
    from (
        select 
            d.*, sum(flag) over(order by ts) as s
        from (select d.*, decode(status,'A',1,0) as flag from data d) d
    ) d
)
where status = 'A'
order by ts
;

一旦您決定了“訂單”列,一種可能的解決方案是:

with data(ord, amount, status) as (
    select 1, 10, 'A' from dual union all
    select 2, 10, 'B' from dual union all
    select 3, 15, 'B' from dual union all
    select 4, 10, 'C' from dual union all
    select 5, 12, 'D' from dual union all
    select 6, 20, 'A' from dual union all
    select 7, 25, 'B' from dual union all
    select 8, 17, 'C' from dual union all
    select 9, 19, 'D' from dual 
),
pdata as (
    select d.*, case status when 'A' then lv else last_value(lv) ignore nulls over(order by ord) end as llv
    from (
        select d.*, 
            nvl(last_value(case status when 'A' then ord end) over(partition by status order by ord
                RANGE BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
            ), case status when 'A' then ord - 1 
            end) as lv
        from data d
    ) d
)
select sum(amount) from pdata
where llv is not null
group by llv
;

sum(amount)
57
81

請注意,將“when 'A' then lv else”替換為“when 'A' then null else”將給出嚴格介於 2 個“A”(不包括第一個)之間的行總和。

這是另一種可能性,假設表名是Tmp


DROP PROCEDURE IF EXISTS summing;
DELIMITER |
CREATE PROCEDURE summing()
    BEGIN
        DECLARE _begin INT DEFAULT NULL;
        DECLARE _end INT DEFAULT NULL;
        
        SELECT `timestamp` INTO _begin FROM Tmp WHERE status='A' ORDER BY `timestamp` LIMIT 1;
        
        IF _begin IS NOT NULL THEN
            
            SELECT `timestamp` INTO _end FROM Tmp WHERE  status='A' AND `timestamp` > _begin ORDER BY `timestamp` LIMIT 1;
            WHILE _end IS NOT NULL DO
                SELECT SUM(amount) FROM Tmp WHERE `timestamp` > _begin AND `timestamp` < _end;
                SET _begin = _end;
                SET _end = NULL;
                SELECT `timestamp` INTO _end FROM Tmp WHERE  status='A' AND `timestamp` > _begin ORDER BY `timestamp` LIMIT 1;
            END WHILE;
        END IF;
    END|
DELIMITER ;

CALL summing ();

我已經在 MySQL 服務器上測試過了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM