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 小时前
Redis(135)Redis的网络模型是什么?
网络·数据库·redis
L.EscaRC2 小时前
Redis大Key与内存不足问题深度解析与应对策略
数据库·redis·缓存
雲烟2 小时前
Qt SQLite在I.mx8上使用问题
数据库·qt·i.mx8
合作小小程序员小小店2 小时前
web开发,在线%药店管理%系统,基于Idea,html,css,jQuery,java,ssm,mysql。
java·前端·mysql·jdk·html·intellij-idea
TDengine (老段)2 小时前
TDengine 转换函数 CAST 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ2 小时前
java实现校验sql中,表字段在表里是否都存在,不存在的给删除掉
java·sql
苦瓜炒蛋挞3 小时前
小迪安全第二十二天-安全开发-PHP应用&数据库操作&留言板功能&第三方插件
数据库·网络安全·php·小迪安全
chushiyunen3 小时前
redis命令 geo(对地理坐标的支持)
数据库·redis·缓存
baivfhpwxf20233 小时前
删除数据表SQL,不是删除数据,是删除表结构
数据库·sql