计算每小时累计销售额

计算每小时累计销售额

需求:
使用sql计算出销售订单 从0点到当前小时累计销售, 要求展示每小时的累计销售额(同样每分钟, 每半小时都可以使用此方法得出)
订单表:t_sales (order_id: 订单id; order_time: 订单时间(格式:2024-01-06 11:01:08); gmv: 交易金额;)

1- 数据准备
set odps.sql.hive.compatible=true;

WITH t_sales AS (
SELECT * FROM (
  VALUES  (100, '2023-11-21 00:05:32', 100)
        , (101, '2023-11-21 01:09:20', 200)
        , (102, '2023-11-21 04:09:53', 100)
        , (103, '2023-11-21 04:32:20', 300)
        , (104, '2023-11-21 07:05:20', 200)
        , (105, '2023-11-21 09:08:25', 100)
        , (106, '2023-11-21 11:05:20', 100)
        , (107, '2023-11-21 16:05:41', 200)
        , (108, '2023-11-21 20:00:20', 100)
        , (109, '2023-11-21 22:57:00', 300)
        , (110, '2023-11-22 01:10:10', 100)
        , (111, '2023-11-22 05:21:00', 200)
) AS table_name(order_id, order_time, gmv)
)
2- 代码实现
  1. 取出 订单表的最小日期和最大日期
-- 1. 取出 订单表的最小日期和最大日期
SELECT 
      DATE_FORMAT(MIN(order_time),'yyyy-MM-dd 00:00:00') AS min_order_time 
    , DATE_FORMAT(MAX(order_time),'yyyy-MM-dd 23:59:59') AS max_order_time 
FROM t_sales 
;
min_order_timemax_order_time
2023-11-21 00:00:002023-11-22 23:59:59
  1. 利用最小日期和最大日期, 得出连续的小时序列, 从最小日期的0点到最大日期的23点
-- 2. 利用最小日期和最大日期, 得出连续的小时序列, 从最小日期的0点到最大日期的23点
SELECT 
      min_order_time, pos, val
    , FROM_UNIXTIME(UNIX_TIMESTAMP(min_order_time) + pos * 60 * 60, 'yyyy-MM-dd HH') AS hour_rn
FROM (
    SELECT -- 1. 取出 订单表的最小日期和最大日期
          DATE_FORMAT(MIN(order_time),'yyyy-MM-dd 00:00:00') AS min_order_time 
        , DATE_FORMAT(MAX(order_time),'yyyy-MM-dd 23:59:59') AS max_order_time 
    FROM t_sales 
) a 
LATERAL VIEW POSEXPLODE( SPLIT(REPEAT('#,', CAST( (UNIX_TIMESTAMP(max_order_time ) - UNIX_TIMESTAMP(min_order_time) + 1 )/(60*60) AS INT ) ), ',') ) tab as pos,val
-- 注意: 1. 时间戳相减需要加1, 需要计算最大日期最小日期的区间值; 2. 替换时使用双字符串, 切分的时候才不为空
;
min_order_timeposvalhour_rn
2023-11-21 00:00:000#2023-11-21 00
2023-11-21 00:00:001#2023-11-21 01
2023-11-21 00:00:002#2023-11-21 02
2023-11-21 00:00:003#2023-11-21 03
2023-11-21 00:00:004#2023-11-21 04
2023-11-21 00:00:005#2023-11-21 05
2023-11-21 00:00:006#2023-11-21 06
2023-11-21 00:00:007#2023-11-21 07
2023-11-21 00:00:008#2023-11-21 08
2023-11-21 00:00:009#2023-11-21 09
2023-11-21 00:00:0010#2023-11-21 10
2023-11-21 00:00:0023#2023-11-21 23
2023-11-21 00:00:0047#2023-11-22 23
  1. 将小时序列和订单时间(转换成小时), 一一关联
-- 3. 将小时序列和订单时间(转换成小时), 一一关联
SELECT 
      hour_rn
    , NVL(gmv, 0) AS gmv
FROM (
    SELECT -- 2. 利用最小日期和最大日期, 得出连续的小时序列, 从最小日期的0点到最大日期的23点
          FROM_UNIXTIME(UNIX_TIMESTAMP(min_order_time) + pos * 60 * 60, 'yyyy-MM-dd HH') AS hour_rn
    FROM (
        SELECT -- 1. 取出 订单表的最小日期和最大日期
              DATE_FORMAT(MIN(order_time),'yyyy-MM-dd 00:00:00') AS min_order_time 
            , DATE_FORMAT(MAX(order_time),'yyyy-MM-dd 23:59:59') AS max_order_time 
        FROM t_sales 
    ) a 
    LATERAL VIEW POSEXPLODE( SPLIT(REPEAT('#,', CAST( (UNIX_TIMESTAMP(max_order_time ) - UNIX_TIMESTAMP(min_order_time) + 1 )/(60*60) AS INT ) ), ',') ) tab as pos,val
    -- 注意: 1. 时间戳相减需要加1, 需要计算最大日期最小日期的区间值; 2. 替换时使用双字符串, 切分的时候才不为空
) a 
LEFT JOIN 
(
    SELECT 
          SUBSTRING(order_time, 1, 13) AS order_time
        , SUM(gmv) AS gmv
    FROM t_sales
    GROUP BY SUBSTRING(order_time, 1, 13)
) b 
ON a.hour_rn = b.order_time
;
hour_rngmv
2023-11-21 00100
2023-11-21 01200
2023-11-21 020
2023-11-21 030
2023-11-21 04400
2023-11-21 050
2023-11-21 060
2023-11-21 07200
2023-11-21 080
2023-11-21 09100
2023-11-21 100
  1. 使用窗口函数累加求和
-- 4. 使用窗口函数累加求和
SELECT 
      hour_rn
    , SUM(gmv) OVER(PARTITION BY SUBSTRING(hour_rn, 1, 10) ORDER BY hour_rn) AS d_gmv
FROM (
    SELECT -- 3. 将小时序列和订单时间(转换成小时), 一一关联
          hour_rn
        , NVL(gmv, 0) AS gmv
    FROM (
        SELECT -- 2. 利用最小日期和最大日期, 得出连续的小时序列, 从最小日期的0点到最大日期的23点
              FROM_UNIXTIME(UNIX_TIMESTAMP(min_order_time) + pos * 60 * 60, 'yyyy-MM-dd HH') AS hour_rn
        FROM (
            SELECT -- 1. 取出 订单表的最小日期和最大日期
                  DATE_FORMAT(MIN(order_time),'yyyy-MM-dd 00:00:00') AS min_order_time 
                , DATE_FORMAT(MAX(order_time),'yyyy-MM-dd 23:59:59') AS max_order_time 
            FROM t_sales 
        ) a 
        LATERAL VIEW POSEXPLODE( SPLIT(REPEAT('#,', CAST( (UNIX_TIMESTAMP(max_order_time ) - UNIX_TIMESTAMP(min_order_time) + 1 )/(60*60) AS INT ) ), ',') ) tab as pos,val
        -- 注意: 1. 时间戳相减需要加1, 需要计算最大日期最小日期的区间值; 2. 替换时使用双字符串, 切分的时候才不为空
    ) a 
    LEFT JOIN 
    (
        SELECT 
              SUBSTRING(order_time, 1, 13) AS order_time
            , SUM(gmv) AS gmv
        FROM t_sales
        GROUP BY SUBSTRING(order_time, 1, 13)
    ) b 
    ON a.hour_rn = b.order_time
) t
;
hour_rnd_gmv
2023-11-21 00100
2023-11-21 01300
2023-11-21 02300
2023-11-21 03300
2023-11-21 04700
2023-11-21 05700
2023-11-21 06700
2023-11-21 07900
2023-11-21 08900
2023-11-21 091000
2023-11-21 101000
2023-11-21 111100
2023-11-21 121100
2023-11-21 131100
2023-11-21 141100
2023-11-21 151100
2023-11-21 161300
2023-11-21 171300
2023-11-21 181300
2023-11-21 191300
2023-11-21 201400
2023-11-21 211400
2023-11-21 221700
2023-11-21 231700
2023-11-22 000
2023-11-22 01100
2023-11-22 02100
2023-11-22 03100
2023-11-22 04100
2023-11-22 05300
2023-11-22 06300
2023-11-22 23300
3- 总结

本题的核心是找到小时级别的序列,‘统计每年在校人数’ 也是相同类型的题目, 可以熟练使用, 不管是天级别,小时级别,分钟级别 都可以使用次方法实现;
主要使用了 LATERAL VIEW POSEXPLODE() 试图表 + 开窗函数 技术实现;
‘统计每年在校人数’: https://blog.csdn.net/Taerge0110/article/details/135137626?spm=1001.2014.3001.5501

end
  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值