SQL Redshift 如何根据其他列值移动单元格值然后求和

问题描述 投票:0回答:2

数据准备:

CREATE TABLE test_work_day
(
  work_day  integer ,
  send_date DATE ,
  volume  integer,
  week_day varchar,
  hols varchar
);
insert into test_work_day values
(0, '2022-05-21', 0, 'Saturday',null),
(0, '2022-05-22', 0, 'Sunday',null),
(1, '2022-05-23', 0, 'Monday',null),
(1, '2022-05-24', 99, 'Tuesday',null),
(1, '2022-05-25', 111,'Wednesday',null),
(0, '2022-05-26', 154, 'Thursday', 'Public_holiday' ),
(1, '2022-05-27', 200, 'Friday',null),
(0, '2022-05-28', 0, 'Saturday',null),
(0, '2022-05-29', 0, 'Sunday',null),
(0, '2022-05-30', 0, 'Monday', 'Public_holiday'),
(1, '2022-05-31', 164, 'Tuesday',null),
(1, '2022-06-01', 123, 'Wednesday',null),
(1, '2022-06-02', 189, 'Thursday',null),
(1, '2022-06-03', 150, 'Friday',null),
(0, '2022-06-04', 0, 'Saturday',null),
(0, '2022-06-05', 0, 'Sunday',null),
(1, '2022-06-06', 100, 'Monday',null),
(1, '2022-06-07', 200, 'Tuesday',null);

select * from test_work_day;

输出:

当“work_day”列中的值 = 0 时,“volume”列中的值(以及后续值)应向下移动到“work_day”列中的值 = 1 的点。如果连续有 3 个 0该值应移至 work_day = 1 的第一行。交易量应仅与 work_day = 1 对齐

从第一个 work_day = 0 (26/05/2022) 算起的第 8 个日历日,有一个追赶时刻,将前一个值和当前值相加。

所需输出:

提前非常感谢!

sql amazon-redshift window-functions gaps-and-islands
2个回答
0
投票

您的预期结果与您的解释并不完全一致,但这读起来就像一个间隙和岛屿问题,其中每个岛都是一个工作日,之前可能有许多非工作日。

我们可以用窗口总和来识别岛屿(技巧是按降序日期对分区进行排序以匹配您想要的逻辑),然后使用条件表达式:

select work_day, send_date, volume, 
    case when work_day = 1 then sum(volume) over(partition by grp) else volume end as new_volume
from (
    select t.*, sum(work_day) over(order by send_date desc) as grp
    from test_work_day t
) t
order by send_date
工作日 发送日期 音量 新卷
1 2022-05-24 99 99
1 2022-05-25 111 111
0 2022-05-26 154 154
1 2022-05-27 200 354
0 2022-05-28 0 0
0 2022-05-29 0 0
0 2022-05-30 0 0
1 2022-05-31 164 164
1 2022-06-01 123 123
0 2022-06-02 189 189
0 2022-06-03 150 150
1 2022-06-04 0 339
1 2022-06-05 0 0
1 2022-06-06 100 100
1 2022-06-07 200 200

小提琴


0
投票

如果支持WITH表达式:

;WITH cteShiftIndex AS
(
    SELECT work_day,
       send_date,
       volume,
       CASE WHEN Volume = 0 THEN NULL 
            ELSE ROW_NUMBER() OVER 
                (PARTITION BY (CASE WHEN Volume = 0 THEN 0 ELSE 1 END) ORDER BY send_date ASC)
            END AS RowIndex,
       SUM(work_day) OVER (ORDER BY send_date) AS WorkIndex
    FROM test_work_day
)
SELECT 
    cte.work_day,
    cte.send_date,
    cte.Volume,
    CASE WHEN cte.work_day = 0 
         THEN 0 ELSE cte2.volume
         END AS VolumeAdjusted
FROM cteShiftIndex cte
    LEFT JOIN cteShiftIndex cte2 ON cte.WorkIndex = cte2.RowIndex
ORDER BY cte.send_date

已更新(带有 SUM 逻辑)

;WITH cteShiftIndex AS
(
    SELECT work_day,
       send_date,
       volume,
       CASE WHEN Volume = 0 THEN NULL 
            ELSE ROW_NUMBER() OVER 
                (PARTITION BY (CASE WHEN Volume = 0 THEN 0 ELSE 1 END) ORDER BY send_date ASC)
            END AS RowIndex,
       SUM(work_day) OVER (ORDER BY send_date) AS WorkIndex
    FROM test_work_day
)
, cteGroupedShiftIndex AS
(
    SELECT *,
        SUM(volume) OVER (ORDER BY send_date) AS TotalVolume,
        DENSE_RANK() OVER (ORDER BY CEILING(WorkIndex / 7.0)) AS GroupIndex
    FROM cteShiftIndex
)
SELECT 
    cte.work_day,
    cte.send_date,
    cte.Volume,
    CASE WHEN cte.work_day = 0 THEN 0
         WHEN cte.WorkIndex % 7 = 0 THEN -- to do the SUM every 7th working day
                cte2.Volume +
                SUM(cte.Volume) OVER (PARTITION BY cte2.GroupIndex ORDER BY cte.send_date) - 
                SUM(CASE WHEN cte.work_day = 0 
                         THEN 0
                         ELSE cte2.volume END) OVER (PARTITION BY cte2.GroupIndex ORDER BY cte.send_date)
         ELSE cte2.volume
    END AS VolumeAdjusted
FROM cteGroupedShiftIndex cte
    LEFT JOIN cteGroupedShiftIndex cte2 ON (cte.WorkIndex + cte.GroupIndex - 1) = cte2.RowIndex
ORDER BY cte.send_date
© www.soinside.com 2019 - 2024. All rights reserved.