SQL滚动求和

需求1:滚动计算10月每天 当天至+25天 范围内 总配货门店数和箱数
  1. 基础表:对底表聚合去重,将日期转为日期格式
sql 复制代码
-- 天商品仓库 门店配货表
DROP TABLE IF EXISTS h_tmp.tmp_base ;
CREATE TABLE h_tmp.tmp_base AS
SELECT
    TO_DATE(order_time) as dt
    ,h_code  -- 商品编码
    ,wrh_name -- 仓库名称
    ,shop_code -- 配货门店
    ,sum(stock_box) as inflow_qty -- 配货箱数
FROM  base 
WHERE dt =DATE_SUB(CURRENT_DATE,1)) 
AND is_send=1
AND DATE_FORMAT(order_time,'yyyy-MM-dd') BETWEEN  '2025-10-01' AND '2025-10-31' 
GROUP BY TO_DATE(order_time),wrh_name,shop_code,h_code
;

-- 取10-01的数,方便后面验证
SELECT COUNT(DISTINCT shop_code) as shop_cnt
,SUM(inflow_qty) as inflow_qty 
FROM h_tmp.tmp_dw_inflow_di_251117
WHERE dt BETWEEN '2025-10-01' AND '2025-10-26'
AND h_code = '123456'
AND wrh_name = '上海仓'
  1. 滚动求和

    • 窗口版 使用 range 限制范围
      PRECEDING 之前
      FOLLOWING 之后
    • 自连接版 限制连接表日期范围
sql 复制代码
-- dt 为统计批次日
-- inflow_26d_shop_cnt 为当天+未来 25 天商品各仓配货总门店数
-- inflow_26d_qty 为当天+未来 25 天商品各仓配货总箱数
-- 方法一 窗口版
DROP TABLE IF EXISTS h_tmp.tmp_ans;
CREATE TABLE h_tmp.tmp_ans AS
SELECT  DISTINCT 
        dt,
        h_code,
        wrh_name,
        SUM(IF(rn=1,1,0)) OVER (PARTITION BY h_code, wrh_name
                                ORDER BY dt --UNIX_TIMESTAMP(dt)
                                RANGE BETWEEN CURRENT ROW AND 25 FOLLOWING) AS inflow_26d_shop_cnt,
        COUNT(DISTINCT shop_code) OVER (PARTITION BY h_code, wrh_name
                                ORDER BY dt 
                                RANGE BETWEEN CURRENT ROW AND 25 FOLLOWING) AS inflow_26d_shop_cnt2,
        SUM(inflow_qty)   OVER (PARTITION BY h_code, wrh_name
                                ORDER BY dt 
                                RANGE BETWEEN CURRENT ROW AND 25 FOLLOWING) AS inflow_26d_qty
FROM (
        SELECT  dt,
                h_code,
                wrh_name,
                shop_code,
                inflow_qty,
                ROW_NUMBER() OVER (PARTITION BY h_code, wrh_name,shop_code
                                   ORDER BY dt) AS rn -- 每个商品仓库门店 根据时间顺序标记,在滚动计算时只计算首次出现的门店
        FROM    h_tmp.tmp_base 
) t
;

--  验证结果与步骤1是否一致
SELECT * 
FROM   h_tmp.tmp_ans
WHERE dt = '2025-10-01'
AND h_code = '123456'
AND wrh_name = '上海仓'

-- 方法二 自连接
DROP TABLE IF EXISTS h_tmp.tmp_ans2;
CREATE TABLE h_tmp.tmp_ans2 AS
SELECT
    t1.dt
    ,t1.h_code
    ,t1.wrh_name
    ,COUNT(DISTINCT t2.shop_code) AS inflow_26d_shop_cnt
    ,SUM(t2.inflow_qty)           AS inflow_26d_qty
FROM (
    -- 先把起点压成 (dt,h_code,wrh_name) 唯一行,再自连接(26 天滚动)
    SELECT dt, h_code, wrh_name
    FROM   h_tmp.tmp_base 
    GROUP  BY dt, h_code, wrh_name
) t1
LEFT JOIN h_tmp.tmp_base t2
ON t1.h_code   = t2.h_code
AND t1.wrh_name = t2.wrh_name
AND t2.dt BETWEEN t1.dt AND date_add(t1.dt,25)
GROUP BY t1.dt, t1.h_code, t1.wrh_name;

--  验证结果与步骤1是否一致
SELECT * 
FROM   h_tmp.tmp_ans2
WHERE dt = '2025-10-01'
AND h_code = '123456'
AND wrh_name = '上海仓'


-- 方法三 自连接 + if
DROP TABLE IF EXISTS h_tmp.tmp_ans3;
CREATE TABLE h_tmp.tmp_ans3 AS
SELECT
    t1.dt
    ,t1.h_code
    ,t1.wrh_name
    ,COUNT(DISTINCT if(t2.dt BETWEEN t1.dt AND date_add(t1.dt,25),t2.shop_code,null)) AS inflow_26d_shop_cnt
    ,SUM(if(t2.dt BETWEEN t1.dt AND date_add(t1.dt,25),t2.inflow_qty,0)  )         AS inflow_26d_qty
FROM (
    -- 先把起点压成 (dt,h_code,wrh_name) 唯一行,再自连接(26 天滚动)
    -- t1 侧同一天如果有 N 行(哪怕完全相同的门店),就会把 t2 的箱数重复加 N 次
    SELECT dt, h_code, wrh_name
    FROM   h_tmp.tmp_base 
    GROUP  BY dt, h_code, wrh_name
) t1
LEFT JOIN h_tmp.tmp_base t2
ON t1.h_code   = t2.h_code
AND t1.wrh_name = t2.wrh_name
GROUP BY t1.dt, t1.h_code, t1.wrh_name;

--  验证结果与步骤1是否一致
SELECT * 
FROM   h_tmp.tmp_ans3
WHERE dt = '2025-10-01'
AND h_code = '123456'
AND wrh_name = '上海仓'
需求2 入库时间滚动25天配货门店数和箱数
sql 复制代码
DROP TABLE IF EXISTS h_tmp.wh_in ;
CREATE TABLE h_tmp.wh_in AS
SELECT
    DATE_FORMAT(order_time,'yyyy-MM-dd') as dt  -- 入库时间
    ,h_code  -- 商品编码
    ,wrh_name -- 入库仓库(wrh_name)
    ,DATE_ADD(order_time,25) as dt_25 -- 25天后的时间
FROM  h_dw.stock_im--入库
WHERE dt = '2025-11-17' 
AND qty>0
AND DATE_FORMAT(order_time,'yyyy-MM-dd') BETWEEN  '2025-10-01' AND '2025-11-01' 
GROUP BY DATE_FORMAT(order_time,'yyyy-MM-dd'),DATE_ADD(order_time,25)
,wrh_name,h_code
;

SELECT  
    a.h_code
    ,a.wrh_name
    ,a.dt
    ,a.dt_25
    ,COUNT(distinct if(b.dt BETWEEN a.dt AND a.dt_25,b.shop_code,null) ) AS inflow_26d_shop_cnt --入库后25天内的配货门店数
    ,SUM(if(b.dt BETWEEN a.dt AND a.dt_25 , b.inflow_qty,0)) AS inflow_26d_qty  --入库后25天内的配货箱数
FROM h_tmp.wh_in a   -- 天商品仓库 入库表
LEFT JOIN h_tmp.tmp_base b  -- 天商品仓库 配货门店表
ON a.h_code = b.h_code AND a.wrh_name = b.wrh_name 
GROUP BY a.h_code
    ,a.wrh_name
    ,a.dt
    ,a.dt_25
;

相关链接:

  1. MySQL 8.0 参考手册 _ 窗口函数框架规范
相关推荐
山茶花.1 小时前
SQL注入总结
数据库·sql·oracle
m0_736919101 小时前
超越Python:下一步该学什么编程语言?
jvm·数据库·python
m0_748229992 小时前
ThinkPHP快速入门:从零到实战
c语言·开发语言·数据库·学习
阿蒙Amon2 小时前
C#每日面试题-Thread.Sleep和Task.Delay的区别
java·数据库·c#
沉舟侧畔千帆过_2 小时前
一个DBA的真心话:搞定Oracle+PG双库,我就靠这招
数据库·oracle·dba
醉风塘2 小时前
【终极解决方案】Oracle ORA-01795错误:IN列表1000条限制的全面突破指南
数据库·oracle
信创天地2 小时前
从 Oracle 到国产数据库:迁移后成本直降 60%、性能反超 30% 的实战秘籍
数据库·oracle
Mikhail_G2 小时前
Mysql数据库操作指南——排序(零基础篇十)
大数据·数据库·sql·mysql·数据分析
沉舟侧畔千帆过_2 小时前
能源核心系统国产化攻坚:智能电网调度系统从 Oracle 到金仓 KES 迁移实录
数据库·oracle·能源·kingbase·金仓数据库
chengrise2 小时前
Oracle EBS 成本异常排查全指南:差异分摊、成本回滚场景与解决方案
运维·数据库·oracle·erp·ebs