SAP B1 库龄分析报表(SQL版本&非批次管理)

SQL版本的库龄分析报表,使用存储过程实现,同时支持分支是否启用。

复制代码
CREATE PROCEDURE "IPS_Report_StockAge"
(
  @BPLId NVARCHAR(50),                     -- 分支ID(筛选指定分支,为空时不限制)
  @ItmsGrpCod NVARCHAR(20),                -- 物料组编码(筛选指定物料组,为空时不限制)
  @EndDate DATE                             -- 统计结束日期(所有数据的时间截止点)
)
AS
BEGIN
  SET NOCOUNT ON; -- 关闭计数消息输出,提升执行效率

  ---01 临时表#StockList:筛选截止日期前库存数量不为0的物料清单
  SELECT 
    T0."ItemCode",                          -- 物料编码
    SUM(T0."InQty"-T0."OutQty") AS "Qty"    -- 净库存数量(入库数量 - 出库数量)
    INTO #StockList                         -- 存入临时表,用于后续筛选有效库存物料
  FROM OIVL T0                               -- OIVL:库存交易主表(存储所有库存进出记录)
  INNER JOIN OITM T1 ON T0."ItemCode"= T1."ItemCode" -- 关联物料主表(OITM),获取物料组信息
  INNER JOIN OWHS T2 ON T0."LocCode"= T2."WhsCode"   -- 关联仓库表(OWHS),获取仓库所属分支信息
  WHERE 1=1
    AND T0."DocDate"<=@EndDate                      -- 交易日期不晚于统计截止日期
    AND (T1."ItmsGrpCod"=@ItmsGrpCod OR ISNULL(@ItmsGrpCod,'')='') -- 物料组筛选(为空时不限制)
    AND (CAST(T2."BPLid" AS NVARCHAR(50))=@BPLId OR ISNULL(@BPLId,'')='') -- 分支筛选(仓库BPLId转字符串匹配,为空时不限制)
  GROUP BY T0."ItemCode"                            -- 按物料编码分组,计算每个物料的总库存
  HAVING SUM(T0."InQty"-T0."OutQty")<>0;            -- 仅保留净库存不为0的物料

  ---02 临时表#StockIn:获取有效库存物料的入库交易明细(含累计入库量和排序ID)
  SELECT 
    T0."ItemCode",                          -- 物料编码
    T0."DocDate",                           -- 入库交易日期
    T0."TransType",                         -- 交易类型(区分不同入库业务,如采购入库、生产入库等)
    T0."CreatedBy",                         -- 制单人
    T0."BASE_REF",                          -- 源单据编号(关联原始业务单据)
    T0."DocLineNum",                        -- 单据行号
    T0."InQty",                             -- 本次入库数量
    -- 按物料编码分区,交易日期倒序、交易序号倒序排序,生成入库记录序号(最新入库为ID=1)
    ROW_NUMBER() OVER(PARTITION BY T0."ItemCode" ORDER BY T0."DocDate" DESC,T0."TransSeq" DESC) AS "ID",
    -- 按物料编码分区,累计入库数量(从最新入库开始累加,用于匹配当前库存)
    SUM(T0."InQty") OVER(PARTITION BY T0."ItemCode" ORDER BY T0."ItemCode",T0."DocDate" DESC,T0."TransSeq" DESC ) AS "SumQty",
    T1."Qty"                                -- 关联#StockList获取该物料的当前总库存
      INTO #StockIn                         -- 存入临时表,用于后续库龄计算
  FROM OIVL T0                               -- OIVL:库存交易主表
  INNER JOIN #StockList T1 ON T0."ItemCode"= T1."ItemCode" -- 仅保留库存非零的物料
  INNER JOIN OWHS T2 ON T0."LocCode"= T2."WhsCode" 
    AND (CAST(T2."BPLid" AS NVARCHAR(100))=@BPLId OR T2."BPLid" IS NULL) -- 分支筛选(含仓库BPLId为空的情况)
  WHERE EXISTS(SELECT 1 FROM #StockList U0 WHERE T0."ItemCode"=U0."ItemCode" ) -- 二次确认库存非零(冗余筛选,提升稳定性)
    AND T0."InQty">0                          -- 仅保留入库记录(排除出库记录)
    AND T0."TransType"<>'67'                  -- 排除交易类型为67的记录(通常为无效或冲销交易)
    AND T0."DocDate"<@EndDate;                -- 交易日期早于截止日期(截止日期当天入库不计入库龄计算)
   
  -- 临时表#MinID:获取每个物料满足当前库存的最小入库记录ID(即覆盖库存所需的最早入库批次)
  SELECT 
    T0."ItemCode",                          -- 物料编码
    MIN(T0.ID) AS "ID",                      -- 满足库存的最小入库记录ID(分界点ID)
    MAX(T0."DocDate") AS "MinDocDate"        -- 该物料的最早入库日期(对应分界点及之前的入库记录)
      INTO #MinID
  FROM #StockIn T0
  WHERE T0."SumQty">=T0."Qty"                -- 累计入库量>=当前库存(找到覆盖库存的所有入库记录)
  GROUP BY T0."ItemCode";
  
  -- 临时表#DATA:计算每个入库批次对应的有效库龄库存(AgaQty)及关键日期
  SELECT 
    T0."ItemCode",                          -- 物料编码
    T0."DocDate",                           -- 入库日期
    T0."TransType",                         -- 交易类型
    T0."CreatedBy",                         -- 制单人
    T0."BASE_REF",                          -- 源单据编号
    T0."DocLineNum",                        -- 单据行号
    T0."InQty",                             -- 本次入库数量
    T0."Qty",                               -- 当前总库存
    T0."SumQty",                            -- 累计入库量
    T0."ID",                                -- 入库记录序号(倒序)
    T1."ID" AS "MinID",                     -- 覆盖库存的最小分界点ID
    -- 有效库龄库存计算:
    -- 1. 序号<分界点ID:该批次入库量全额计入(已完全覆盖库存)
    -- 2. 序号=分界点ID:用总库存 - 上一批次累计入库量(剩余库存计入当前批次)
    CASE WHEN T0."ID"1096 THEN T0."AgaQty" ELSE 0 END) AS "三年以上" -- 库龄>3年的库存(1096=365*3+1)
  FROM #DATA T0                               -- 基于库龄计算中间表聚合
  INNER JOIN OITM T1 ON T0."ItemCode"= T1."ItemCode" -- 关联物料主表,获取物料描述
  INNER JOIN OITB T2 ON T1."ItmsGrpCod" = T2."ItmsGrpCod" -- 关联物料组表,获取物料组名称
  GROUP BY T0."ItemCode",T1."ItemName",T2."ItmsGrpCod",T2."ItmsGrpNam" -- 按物料+物料组分组
  ORDER BY 3,1;                               -- 按物料组编码、物料编码排序输出

  -- 清理临时表(避免占用资源,存储过程结束后临时表会自动删除,此处为冗余处理)
  DROP TABLE IF EXISTS #StockList;
  DROP TABLE IF EXISTS #StockIn;
  DROP TABLE IF EXISTS #MinID;
  DROP TABLE IF EXISTS #DATA;
END
相关推荐
yang982262 小时前
S4 CLOUD
sap
Lethehong4 小时前
Oracle 加个字段,目标库就报错?KFS 用“先拆后组“打通异构 DDL
数据库·oracle
Web极客码4 小时前
锁定真正的磁盘卡顿:我用 OpenCode 配合 eBPF 诊断 NVMe 队列深度延迟与 I/O 写放大
数据库·oracle
cspttty5 小时前
2027用户研究求职准备:应用统计学如何补齐研究设计与业务表达
大数据·数据库
roman_日积跬步-终至千里6 小时前
【数据Agent论文·查询与语义|05】Spider:为什么换一个数据库,模型就不会查了?
数据库·数据分析
猫咪很可爱6 小时前
Oracle RAC 启动失败排查:私网通信与内核参数优化实战
运维·数据库·oracle
XLYcmy7 小时前
《数字经济赋能城市低碳治理的路径研究检索报告》审阅与修改指导意见——基于完整检索报告体例的完整性诊断、学术规范核查与方法论纠偏 上
数据库·ai·chatgpt·文心一言·检索·知网·豆包
泡海椒7 小时前
JQuick-SQL 快速开始:注册内存表并执行查询
数据库·windows·sql
ss2737 小时前
PG实战笔记 | 09 PostgreSQL psql客户端基本操作
数据库·笔记·postgresql
电商API_180079052477 小时前
反向海淘多币种结算:汇率该在哪个时点被冻结
java·开发语言·数据库·跨境电商·1688 api