Подзапрос вернул более 1 значения. Это не разрешено, когда подзапрос используется как выражение

У меня есть хранимая процедура и функция на SQL Server. Но всякий раз, когда я запускаю его, я получаю такую ​​​​ошибку

Подзапрос вернул более 1 значения. Это не разрешено, когда подзапрос следует за =, !=, <, <= , >, >= или когда подзапрос используется как выражение.

Это моя функция CekStokTersedia (для проверки наличия):

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

Тогда это моя хранимая процедура 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

Затем я запускаю процедуру следующим образом:

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

И есть такая ошибка:

Подзапрос вернул более 1 значения. Это не разрешено, когда подзапрос следует за =, !=, <, <= , >, >= или когда подзапрос используется как выражение.

Пожалуйста, помогите мне решить эту проблему...

Ошибка говорит сама за себя, отладьте свой процесс, найдите запрос, который ее вызывает, и исправьте логику. Кому-то другому очень сложно сделать это за вас без доступа к минимально воспроизводимому примеру

Dale K 03.04.2023 08:50
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
1
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы передаете значение '2,10' вместо @qty (т.е. два значения), но попробуйте присвоить это одному значению int здесь:

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

Каких @qtyInt вы ожидаете здесь, 2 или 10, и почему? Вам нужно дать SQL Server правильную логику, чтобы определить, какое значение выбрать, поскольку @qtyInt может содержать только одно значение.

Хотя, просмотрев вашу процедуру, я не думаю, что вам вообще нужно это назначение, ваш курсор уже включает это количество, поэтому вы можете удалить проблемную строку и просто назначить это в своем выборке курсора:

FETCH NEXT FROM menu_cursor INTO @kodesMenu, @qtyInt;

Наконец, хотя я не знаком со всей вашей бизнес-логикой, я был бы очень удивлен, если бы это нельзя было переписать намного более эффективно, используя подход, основанный на наборах. Подобные процедурные подходы обычно плохо масштабируются.

Ответ принят как подходящий

я думаю, что подзапрос возвращает более одного значения, но код пытается сравнить его с одним значением (проблема связана с функцией dbo.CekStokTersedia, которая возвращает более одного значения в определенных сценариях)

причиной ошибки могло быть использование параметра @qtyInt в dbo.CekStokTersedia

@qtyInt — это одно целое значение — запрос внутри функции ожидает сравнения его с несколькими значениями из Stock_Akhir (может привести к тому, что подзапрос вернет несколько значений)

  • вы можете изменить запрос внутри функции, чтобы использовать соединение вместо подзапроса
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
  • мы соединяем Tr_Type_S с двумя временными таблицами @tglCheckin и @tglCheckout, чтобы получить список дат между датами заезда и выезда
  • мы проверяем значение Stock_Akhir для каждой даты
  • вернуть результат в @results (должно вернуть одно значение)

PS. вы можете пересмотреть использование курсоров в хранимой процедуре (они могут быть проблемой производительности и иногда могут приводить к неожиданным результатам) - лучше использовать операции на основе набора вместо курсоров - особенно для больших наборов данных

спасибо за ваше предложение, я изменил запрос, который у меня есть, используя запрос на соединение, и он работает, хотя и с несколькими другими изменениями.

andrea santana 03.04.2023 14:55

Другие вопросы по теме