AI-豆包调试FIFO存储过程

  •  前提说明:以下仅为条码及批次的FIFO管控,条码及批次的规范性,由其他存储已经校验


 

  • FIFO存储 

/****** Object:  StoredProcedure [dbo].[m_St_FIFO_KC]    Script Date: 2026-02-03 10:00:54 ******/
SET ANSI_NULLS ON  -- 开启ANSI空值规范,NULL参与比较时遵循标准规则
GO
SET QUOTED_IDENTIFIER ON  -- 开启引号标识符,双引号仅用于标识对象名
GO
-- 修改先进先出(FIFO)库存校验存储过程,首次创建请替换为CREATE PROCEDURE
ALTER PROCEDURE [dbo].[m_St_FIFO_KC]
    @FCode VARCHAR(200),        -- 输入:待校验的当前条码
    @FCodes VARCHAR(2000),      -- 输入:批量条码集合(逗号分隔,用于扣减对应库存)
    @Sstatus VARCHAR(2000) OUTPUT, -- 输出:校验状态码 000000=通过 999999=失败
    @FError VARCHAR(MAX) OUTPUT    -- 输出:校验信息,失败时返回详细违规原因
WITH EXECUTE AS CALLER  -- 以调用该存储过程的用户身份执行,遵循调用者权限
AS
BEGIN
    -- 会话环境配置:提升执行效率+保证事务稳定性+统一周数计算规则
    SET NOCOUNT ON;        -- 屏蔽查询返回的"受影响行数"提示,减少网络传输
    SET XACT_ABORT ON;     -- 事务执行出错时立即回滚并终止,避免脏数据
    SET DATEFIRST 1;       -- 设置一周的第一天为周一,保证周数计算统一(与企业批次管理一致)

    -- 初始化校验状态:默认校验通过
    SELECT @Sstatus='000000',@FError='校验通过!';

    -- 声明核心变量:存储中间计算结果和查询值
    DECLARE
        @FProductID INT=0,        -- 当前条码对应的产品ID
        @FWorkShipID INT=0,       -- 当前条码对应的车间ID
        @FBatchNo_Cur VARCHAR(50)='', -- 当前条码对应的批次号
        @FYear INT=0,             -- 当前批次解析后的年份
        @FZS INT=0,               -- 当前批次解析后的年度周数(ZS=周数)
        @FYear_KC INT=0,          -- 库存中最早批次的年份(KC=库存)
        @FZS_KC INT=0,            -- 库存中最早批次的年度周数
        @Earliest_Code VARCHAR(200)='无', -- 库存最早批次对应的条码
        @Earliest_BatchNo VARCHAR(50)=''; -- 库存中最早的批次号

    -- 步骤1:根据待校验条码,查询产品ID、车间ID、当前批次号
    SELECT 
        @FProductID=ISNULL(FProductID,0),  -- 空值转为0,避免后续计算报错
        @FWorkShipID=ISNULL(FWorkShipID,0),
        @FBatchNo_Cur=ISNULL(FBatchNo,'')  -- 空值转为空字符串
    FROM TM_CodeInfo  -- 条码基础信息表
    WHERE FCode=@FCode; -- 按条码精准查询

    -- 步骤2:解析当前批次号,提取年份和年度周数(仅当批次号非空时执行)
    IF @FBatchNo_Cur<>''
    BEGIN
        -- 截取批次号前8位作为日期前缀(去除前后空格)
        DECLARE @BatchPre VARCHAR(8)=LEFT(LTRIM(RTRIM(@FBatchNo_Cur)),8);
        -- 解析日期前缀为标准DATE类型,兼容2种格式:8位(YYYYMMDD)、6位(YYMMDD)
        DECLARE @TargetDate DATE=CASE
            -- 8位前缀(如20260203),验证为有效日期后按112格式(YYYYMMDD)转换
            WHEN LEN(@BatchPre)=8 AND ISDATE(@BatchPre)=1 THEN TRY_CONVERT(DATE,@BatchPre,112)
            -- 6位前缀(如260203),补全20后验证并转换(如20260203)
            WHEN LEN(@BatchPre)=6 AND ISDATE('20'+@BatchPre)=1 THEN TRY_CONVERT(DATE,'20'+@BatchPre,112)
            ELSE NULL END; -- 解析失败返回NULL

        -- 日期解析成功时,计算年份和年度周数
        IF @TargetDate IS NOT NULL
            SELECT 
                @FYear=YEAR(@TargetDate),  -- 提取年份
                -- 计算年度周数:当年1月1日到目标日期的天数,向上取整为周(每周7天)
                @FZS=(DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,@TargetDate),0),@TargetDate)+7)/7;
    END

    -- 步骤3:拆分批量条码,创建临时表#FCodes(存储单行条码)
    -- F_Splitstr:自定义字符串拆分函数,按逗号拆分@FCodes为多行
    SELECT F1 AS FCode INTO #FCodes 
    FROM F_Splitstr(ISNULL(@FCodes,''),','); -- 空值处理,避免拆分函数报错

    -- 步骤4:统计批量条码对应的库存总量,创建临时表#temp_KC
    SELECT 
        t1.FBatchNo,        -- 批次号
        t1.FProductID,      -- 产品ID
        t1.FWorkShipID,     -- 车间ID
        t1.FDepotID,        -- 仓库ID
        SUM(ISNULL(t1.FlabelNum,0))AS FNumA  -- 统计库存数量(空值转0后求和)
    INTO #temp_KC  -- 结果存入临时表
    FROM #FCodes t0  -- 拆分后的批量条码
    JOIN TM_CodeInfo t1 WITH(NOLOCK) ON t0.FCode=t1.FCode  -- 关联条码信息表,NOLOCK:读未提交,提升并发
    -- 按批次/产品/车间/仓库分组,保证库存统计粒度准确
    GROUP BY t1.FBatchNo,t1.FProductID,t1.FWorkShipID,t1.FDepotID;

    -- 步骤5:计算库存台账中「实际可用库存批次」,创建临时表#temp_ZSKC
    -- 核心逻辑:台账库存 - 批量条码库存 = 实际可用库存,筛选可用库存>0的有效批次
    SELECT 
        t0.FBatchNo,  -- 批次号
        -- 计算实际可用库存数:台账库存 - 批量条码库存(空值均转0)
        ISNULL(t0.FNumA-ISNULL(t1.FNumA,0),0)AS FNumA,
        -- 解析批次号为年份和年度周数(与步骤2逻辑一致)
        YEAR(dt.Batch_Date)AS FYear,
        (DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,dt.Batch_Date),0),dt.Batch_Date)+7)/7AS FZS
    INTO #temp_ZSKC  -- 结果存入临时表(库存有效批次核心表)
    FROM St_InventoryAccount t0 WITH(NOLOCK)  -- 库存台账表,NOLOCK提升并发
    -- 交叉应用:解析台账中批次号为标准日期(Batch_Date)
    CROSS APPLY(
        SELECT CASE
            WHEN ISDATE(LEFT(t0.FBatchNo,8))=1 THEN CASE
                WHEN LEN(LEFT(t0.FBatchNo,8))=8 THEN TRY_CONVERT(DATE,LEFT(t0.FBatchNo,8),112)
                WHEN LEN(LEFT(t0.FBatchNo,8))=6 THEN TRY_CONVERT(DATE,'20'+LEFT(t0.FBatchNo,8),112)
                ELSE NULL END 
            ELSE NULL END AS Batch_Date
    )dt
    -- 左关联批量条码库存表,用于扣减库存
    LEFT JOIN #temp_KC t1 
        ON t0.FWorkShipID=t1.FWorkShipID AND t0.FDepotID=t1.FDepotID
        AND t0.FBatchNo=t1.FBatchNo AND t0.FProductID=t1.FProductID
    -- 筛选条件:仅保留有效库存批次
    WHERE 
        ISNULL(t0.FNumA-ISNULL(t1.FNumA,0),0)>0 AND  -- 实际可用库存>0
        dt.Batch_Date IS NOT NULL AND                -- 批次号日期解析有效
        t0.FProductID=@FProductID AND                -- 与当前条码同产品
        t0.FWorkShipID=@FWorkShipID;                 -- 与当前条码同车间

    -- 步骤6:FIFO核心校验(仅当当前批次解析有效+存在库存有效批次时执行)
    IF @FYear>0 AND @FZS>0 AND EXISTS(SELECT 1 FROM #temp_ZSKC)
    BEGIN
        -- 取库存中最早的批次:按年份升序、周数升序,取第一条(先进先出核心)
        SELECT TOP 1 
            @FYear_KC=FYear,
            @FZS_KC=FZS,
            @Earliest_BatchNo=FBatchNo 
        FROM #temp_ZSKC 
        ORDER BY FYear ASC,FZS ASC;

        -- 判定FIFO违规:当前批次晚于库存最早批次(后入库批次不能先使用)
        IF (@FYear > @FYear_KC) OR (@FYear = @FYear_KC AND @FZS > @FZS_KC)
        BEGIN
            -- 查询库存最早批次对应的条码(按创建时间、ID升序,取最早创建的条码)
            SELECT TOP 1 @Earliest_Code=ISNULL(FCode,'无')
            FROM TM_Codeinfo t
            -- 解析批次号为日期
            CROSS APPLY(
                SELECT CASE
                    WHEN LEN(LEFT(LTRIM(RTRIM(t.FBatchNo)),8))=8 AND ISDATE(LEFT(t.FBatchNo,8))=1 
                        THEN TRY_CONVERT(DATE,LEFT(t.FBatchNo,8),112)
                    WHEN LEN(LEFT(LTRIM(RTRIM(t.FBatchNo)),6))=6 AND ISDATE('20'+LEFT(t.FBatchNo,6))=1 
                        THEN TRY_CONVERT(DATE,'20'+LEFT(t.FBatchNo,6),112)
                    ELSE NULL END AS Batch_Date
            )dt
            -- 解析批次号为年份和周数
            CROSS APPLY(
                SELECT YEAR(dt.Batch_Date)AS Batch_Year,
                    (DATEDIFF(DAY,DATEADD(YEAR,DATEDIFF(YEAR,0,dt.Batch_Date),0),dt.Batch_Date)+7)/7AS Batch_Week
            )wk
            -- 筛选条件:与库存最早批次同产品、同车间、同年、同周,且日期解析有效
            WHERE wk.Batch_Year=@FYear_KC AND wk.Batch_Week=@FZS_KC AND dt.Batch_Date IS NOT NULL
                AND t.FProductID=@FProductID AND t.FWorkShipID=@FWorkShipID
            -- 排序规则:按条码创建时间、ID升序,取最早生成的条码
            ORDER BY t.FCreateDate ASC,t.FID ASC;

            -- 设置FIFO违规状态和详细错误信息
            SET @Sstatus='999999'; -- 失败状态码
            SET @FError='先进先出校验失败!'+CHAR(13)+CHAR(10) -- 换行符
                +'当前条码:'+@FCode+'(批次:'+@FBatchNo_Cur+','+CAST(@FYear AS VARCHAR(4))+'年第'+CAST(@FZS AS VARCHAR(2))+'周)'+CHAR(13)+CHAR(10)
                +'最早条码:'+@Earliest_Code+'(批次:'+@Earliest_BatchNo+','+CAST(@FYear_KC AS VARCHAR(4))+'年第'+CAST(@FZS_KC AS VARCHAR(2))+'周)';
        END
    END

    -- 步骤7:清理临时表资源,避免会话残留
    DROP TABLE IF EXISTS #FCodes,#temp_KC,#temp_ZSKC;
    -- 恢复系统默认周起始日:将周一改回周日,不影响其他数据库会话
    SET DATEFIRST 7;
END
GO
  • 测试示例

前提条件

  • 基础表数据准备

TM_CodeInfo(条码信息表)存在以下测试数据:

FCodeFProductIDFWorkShipIDFBatchNoFCreateDateFID
CODE2026020301 1001 201 2026020301 2026-02-03 09:00:00 1
CODE2026021001 1001 201 2026021001 2026-02-10 10:00:00 2
St_InventoryAccount(库存台账表)存在以下测试数据:
FBatchNoFProductIDFWorkShipIDFDepotIDFNumA
2026020301 1001 201 301 50
2026021001 1001 201 301 30
 

自定义函数:F_Splitstr 函数可正常拆分逗号分隔的字符串。
周数计算规则:2026-02-03 为 2026 年第 5 周,2026-02-10 为 2026 年第 6 周(按中国周,周一为每周第一天)。


 

场景 1:FIFO 校验通过

输入参数

DECLARE @Sstatus VARCHAR(2000), @FError VARCHAR(MAX);
-- 待校验条码:2026020301(2026年第5周)
-- 批量条码:空(无扣减库存)
EXEC [dbo].[m_St_FIFO_KC] 
    @FCode = 'CODE2026020301',
    @FCodes = '',
    @Sstatus = @Sstatus OUTPUT,
    @FError = @FError OUTPUT;

-- 输出结果
SELECT @Sstatus AS 校验状态码, @FError AS 校验信息;

执行逻辑说明

解析当前条码批次号 2026020301 → 日期 2026-02-03 → 2026 年第 5 周。
批量条码 @FCodes 为空 → #FCodes 临时表无数据 → #temp_KC 无数据。
库存台账查询:同产品 1001、同车间 201 的有效批次为 2026020301(50 件)和 2026021001(30 件)。
计算可用库存:50-0=50、30-0=30 → 均大于 0 → 存入 #temp_ZSKC。
取库存最早批次:2026020301(2026 年第 5 周)→ 与当前批次年周一致 → 校验通过。

输出结果

校验状态码校验信息
000000 校验通过!
 

 

场景 2:FIFO 校验失败(核心违规场景)

输入参数

DECLARE @Sstatus VARCHAR(2000), @FError VARCHAR(MAX);
-- 待校验条码:2026021001(2026年第6周)
-- 批量条码:空(无扣减库存)
EXEC [dbo].[m_St_FIFO_KC] 
    @FCode = 'CODE2026021001',
    @FCodes = '',
    @Sstatus = @Sstatus OUTPUT,
    @FError = @FError OUTPUT;

-- 输出结果
SELECT @Sstatus AS 校验状态码, @FError AS 校验信息;

执行逻辑说明

解析当前条码批次号 2026021001 → 日期 2026-02-10 → 2026 年第 6 周。
#temp_KC 无数据 → 库存台账可用批次仍为 2026020301(50 件)、2026021001(30 件)。
取库存最早批次:2026020301(2026 年第 5 周)。
对比判定:当前批次周数 6 > 5 → 违反先进先出规则 → 校验失败。
查询最早批次对应的条码 → CODE2026020301。

输出结果

校验状态码校验信息
999999 先进先出校验失败!
 
当前条码:CODE2026021001(批次:2026021001,2026 年第 6 周)
 
最早条码:CODE2026020301(批次:2026020301,2026 年第 5 周)

 

posted @ 2026-02-03 15:26  大白菜!  阅读(3)  评论(0)    收藏  举报