You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server存储过程报错:子查询返回多个值问题求助

问题排查:SQL Server存储过程执行报错“Subquery returned more than 1 value”

错误信息

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

错误原因分析

  1. 存储过程变量赋值错误:
    存储过程中DECLARE @qtyInt AS int = (SELECT CAST(value AS int) FROM STRING_SPLIT(@qty, ','));语句,当传入的@qty包含多个值(如示例中的'2,10')时,STRING_SPLIT返回多行结果,直接赋值给单个int变量会触发报错。此外,该变量逻辑错误,每个菜单对应独立需求量,不应使用全局变量存储。

  2. 自定义函数逻辑冗余:
    函数CekStokTersedia使用临时表存储每日库存检查结果,写法冗余,可通过聚合函数简化判断逻辑,避免不必要的临时表操作。

修复方案

1. 修复存储过程CheckStockMenu

移除错误的全局变量@qtyInt,在循环中从临时表获取当前菜单对应的需求量;优化字符串拆分关联逻辑,兼容SQL Server 2017及更早版本:

USE [Hotel]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--EXEC [dbo].[CheckStockMenu] '2023-04-01', '2023-04-03', 'PA03,PA02', '2,10'
ALTER PROCEDURE [dbo].[CheckStockMenu]
    @Checkin datetime,
    @Checkout datetime,
    @MenuKode varchar(100),
    @qty varchar(100)
AS
BEGIN
     SET NOCOUNT ON;
    DECLARE @stokTersedia bit = 1;
    DECLARE @menuKodes TABLE (rn int, kode varchar(100), qty int);
    DECLARE @menuKodeTidakCukup varchar(100) = '';

    -- 拆分菜单和数量并关联,用ROW_NUMBER兼容旧版本SQL Server
    INSERT INTO @menuKodes (rn, kode, qty)
    SELECT 
        k.rn, k.value, CAST(q.value AS int)
    FROM (
        SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rn
        FROM STRING_SPLIT(@MenuKode, ',')
    ) AS k
    JOIN (
        SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rn
        FROM STRING_SPLIT(@qty, ',')
    ) AS q ON k.rn = q.rn

    DECLARE @kodesMenu varchar(100);
    DECLARE @currentQty int;
    -- 游标同时获取菜单编码和对应需求量
    DECLARE menu_cursor CURSOR FOR SELECT kode, qty FROM @menuKodes;
    OPEN menu_cursor;
    FETCH NEXT FROM menu_cursor INTO @kodesMenu, @currentQty;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        -- 检查日期范围内是否每天都有库存记录
        IF (SELECT COUNT(tanggal) FROM Tr_Type_S WHERE T_Type = @kodesMenu AND tanggal >= @Checkin AND tanggal <= @Checkout) <> DATEDIFF(day, @Checkin, @Checkout) + 1
        BEGIN
            SET @stokTersedia = 0;
            SET @menuKodeTidakCukup = CONCAT(@menuKodeTidakCukup, @kodesMenu, ', ');
        END
        -- 调用函数检查当前菜单的库存是否满足对应需求量
        ELSE IF dbo.CekStokTersedia(@Checkin, @Checkout, @currentQty, @kodesMenu) = 0
        BEGIN
            SET @stokTersedia = 0;
            SET @menuKodeTidakCukup = CONCAT(@menuKodeTidakCukup, @kodesMenu, ', ');
        END
        FETCH NEXT FROM menu_cursor INTO @kodesMenu, @currentQty;
    END
    CLOSE menu_cursor;
    DEALLOCATE menu_cursor;
    
    IF @stokTersedia = 1
        SELECT 'Stok tersedia' AS Status;
    ELSE
        SELECT CONCAT('Stok tidak cukup untuk menu dengan kode ', LEFT(@menuKodeTidakCukup, LEN(@menuKodeTidakCukup) - 1)) AS Status;
END

2. 修复自定义函数CekStokTersedia

简化逻辑,直接通过聚合函数判断日期范围内是否存在库存不足的情况,移除临时表操作:

USE [Hotel]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[CekStokTersedia] (@tglCheckin datetime, @tglCheckout datetime, @qty int, @kodeMenu varchar(100))
RETURNS bit
AS
BEGIN
    DECLARE @result bit = 1;

    -- 检查日期范围内是否有任何一天库存不足
    IF EXISTS (
        SELECT 1 
        FROM Tr_Type_S 
        WHERE T_Type = @kodeMenu 
          AND tanggal >= @tglCheckin 
          AND tanggal <= @tglCheckout
          AND ISNULL(Stock_Akhir, 0) < @qty
    )
        SET @result = 0;

    -- 检查日期范围内是否存在缺失的记录
    IF NOT EXISTS (
        SELECT 1 
        FROM Tr_Type_S 
        WHERE T_Type = @kodeMenu 
          AND tanggal >= @tglCheckin 
          AND tanggal <= @tglCheckout
    )
        SET @result = 0;

    RETURN @result
END

测试执行

执行原测试语句验证修复效果:

EXEC [dbo].[CheckStockMenu] '2023-04-01', '2023-04-03', 'PA03,PA02', '2,10'

内容的提问来源于stack exchange,提问作者andrea santana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:02:56