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 参考手册 _ 窗口函数框架规范
相关推荐
爱学java的ptt2 小时前
mysql的存储引擎
数据库·mysql
小宇的天下2 小时前
innovus Flip chip 产品设计方法(3)
数据库·windows·microsoft
龘龍龙3 小时前
Python基础学习(十一)
python·学习·mysql
GalenZhang8883 小时前
使用 Python SDK 将数据写入飞书多维表格
数据库·python·飞书·多维表格
云和数据.ChenGuang3 小时前
GaussDB 期末考试题与面试题
数据库·opengauss·gaussdb·数据库期末试题
不屈的铝合金3 小时前
SQL 语言概述与数据库核心前置配置了解
数据库·sql·mysql·约束·sql 语句分类·字符集配置·校对规则
萧曵 丶3 小时前
可重复读(Repeatable Read)隔离级别下幻读产生的原因
数据库·sql·mysql
Antoine-zxt3 小时前
MySQL宕机日志迷局破解指南:从前台启动到精准排错
数据库·mysql·adb
松涛和鸣3 小时前
DAY47 FrameBuffer
c语言·数据库·单片机·sqlite·html
阳宗德3 小时前
基于CentOS Linux release 7.1实现了Oracle Database 11g R2 企业版容器化运行
linux·数据库·docker·oracle·centos