SQL Server Subquery returned more than 1 value. This is not permitted when the subquery is used as an expression

uqdfh47h  于 2023-04-04  发布在  其他
关注(0)|答案(2)|浏览(383)

I have a stored procedure and function on SQL Server. But, whenever I run it, I got some error like this
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

This is my function of CekStokTersedia (for checking available stock):

USE [Hotel]
GO
/****** Object:  UserDefinedFunction [dbo].[CekStokTersedia]    Script Date: 03/04/2023 12:20:08 ******/
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 @stok float
    DECLARE @results TABLE (STOK bit)

    INSERT INTO @results (STOK)
    SELECT CASE WHEN ISNULL(Stock_Akhir, 0) >= @qty THEN 1 ELSE 0 END AS STOK
    FROM Tr_Type_S 
    WHERE T_Type = @kodeMenu AND tanggal >= @tglCheckin AND tanggal <= @tglCheckout
    
    DECLARE @result bit
    SELECT @result = STOK FROM @results WHERE STOK = 0
    
    -- tambahkan kondisi pengecekan apakah ada data dengan range tanggal yang dimasukkan
    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

Then, this is my stored procedure CheckStockMenu:

USE [Hotel]
GO
/****** Object:  StoredProcedure [dbo].[CheckStockMenu]    Script Date: 03/04/2023 12:20:29 ******/
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 (kode varchar(100), qty int);
    DECLARE @menuKodeTidakCukup varchar(100) = '';
    DECLARE @qtyInt AS int = (SELECT CAST(value AS int) FROM STRING_SPLIT(@qty, ','));

    INSERT INTO @menuKodes (kode, qty)
    SELECT kode.value, CAST(qty.value AS int)
    FROM STRING_SPLIT(@MenuKode, ',') AS kode 
    JOIN STRING_SPLIT(@qty, ',') AS qty 
    ON kode.[key] = qty.[key]

    DECLARE @kodesMenu varchar(100);
    DECLARE menu_cursor CURSOR FOR SELECT kode FROM @menuKodes;
    OPEN menu_cursor;
    FETCH NEXT FROM menu_cursor INTO @kodesMenu;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        -- Pengecekan apakah data dengan range antara @Checkin dan @Checkout ada atau tidak
        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
        -- Pengecekan stok pada setiap menu yang dimasukkan
        ELSE IF dbo.CekStokTersedia(@Checkin, @Checkout, @qtyInt, @kodesMenu) = 0
        BEGIN
            SET @stokTersedia = 0;
            SET @menuKodeTidakCukup = CONCAT(@menuKodeTidakCukup, @kodesMenu, ', ');
        END
        FETCH NEXT FROM menu_cursor INTO @kodesMenu;
    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

Then, I running the procedure like this:

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

And have an error like this:

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

Please help me to solve this problem...

vyu0f0g1

vyu0f0g11#

i think the subquery returns more than one value -- but the code tries to compare it with a single value(the issue is related to the function dbo.CekStokTersedia which returns more than one value in certain scenarios)

reason for the error could be the use of the @qtyInt parameter in dbo.CekStokTersedia

@qtyInt is a single integer value -- the query inside the function expects to compare it with multiple values from the Stock_Akhir (could lead to a subquery returning multiple values)

  • you can modify the query inside the function to use a join instead of a subquery
INSERT INTO @results (STOK)
SELECT CASE WHEN ISNULL(ts.Stock_Akhir, 0) >= @qty THEN 1 ELSE 0 END AS STOK
FROM @tglCheckin AS ci
INNER JOIN @tglCheckout AS co ON ci.idx = co.idx
INNER JOIN Tr_Type_S ts ON ts.tanggal >= ci.tgl AND ts.tanggal <= co.tgl AND ts.T_Type = @kodeMenu
  • we join Tr_Type_S with two temporary tables @tglCheckin and @tglCheckout to get a list of dates between the check-in and check-out dates
  • we check the Stock_Akhir value for each date
  • return the result in @results (should return a single value)

PS. you may want to review the use of cursors in the stored procedure(they can be a performance issue and can sometimes lead to unexpected results) -- it's better to use set-based operations instead of cursors -- especially for large datasets

ulmd4ohb

ulmd4ohb2#

You are passing the value '2,10' for @qty (i.e. two values) but try to assign this to a single int value here:

DECLARE @qtyInt AS int = (SELECT CAST(value AS int) FROM STRING_SPLIT(@qty, ','));

What are you expecting @qtyInt to be here, 2 or 10, and why? You need to give SQL Server the correct logic to determine which value to chose as @qtyInt can only hold one value.

Although having looked through your procedure I don't think you need this assignment at all, your cursor already includes this quantity, so you can remove the problem line and just assign this within your cursor fetch:

FETCH NEXT FROM menu_cursor INTO @kodesMenu, @qtyInt;

Finally, while I am not familiar with all of your business logic, I'd be very surprised if this couldn't be rewritten a lot more efficiently using a set based approach. Procedural approaches like this typically do not scale well.

相关问题