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 参考手册 _ 窗口函数框架规范
相关推荐
ao_lang12 小时前
MySQL的存储过程和触发器
android·数据库·mysql
小白勇闯网安圈12 小时前
unserialize3、php_rce、Web_php_include、warmup、NewsCenter
sql·网络安全·web
JIngJaneIL12 小时前
基于Java酒店管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
颜颜yan_12 小时前
DevUI自定义开发实践:从零开始构建自定义组件和插件
android·java·数据库
编织幻境的妖12 小时前
数据库隔离级别详解与选择
数据库
wljt12 小时前
达梦导入大数据
数据库
马克学长13 小时前
SSM物流系统h7fel(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm框架·物流管理系统
ZePingPingZe13 小时前
Spring Boot + MySQL读写分离实现方案
spring boot·mysql·adb
一颗宁檬不酸13 小时前
Oracle序列从2开始而不是从1开始的常见原因及解决方法
数据库·oracle
VX:Fegn089513 小时前
计算机毕业设计|基于springboot + vue健身房管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计