Строка целочисленных значений, содержащихся в переменной varchar, не работает в предложении HAVING ... IN в хранимой процедуре - PullRequest
0 голосов
/ 30 июня 2011

Вот пример оператора в хранимой процедуре:

  SELECT @nDBNum = Num
    FROM Num_members
GROUP BY Num
  HAVING SUM(CASE WHEN Part_No IN (@strOrderedString) THEN 1 ELSE 0 END) = @nCount
     AND COUNT(*) = @nCount

Если переменная @strOrderedString в предложении "IN" содержит только одно число, все работает нормально.Однако, если в этой строке есть список чисел, разделенных запятыми, я получаю синтаксическую ошибку при выполнении хранимой процедуры (например: синтаксическая ошибка при преобразовании значения varchar '1259,2423,2701,2415,2453' в столбец типа данных int.)

Как мне заставить этот запрос работать?

Ответы [ 3 ]

1 голос
/ 30 июня 2011

Вы получаете ошибку, потому что SQL не поддерживает переменную для представления списка значений, разделенных запятыми, для предложения IN - он ожидает переменную для каждого значения с запятыми, определенными в SQL.Вам нужно использовать динамический SQL, где SQL - это строка, соединенная перед выполнением, для того, что вы опубликовали для работы.

Поскольку вы используете SQL Server 2000, вам нужно использовать EXEC / EXECUTE для выполнения динамического SQL.sp_executesql - это SQL Server 2005 +.

0 голосов
/ 30 июня 2011

Вы можете передать значения в качестве параметра XML в хранимую процедуру.

<Ids>
    <Id>1</Id>
    <Id>2</Id>
    <Id>3</Id>
    <Id>4</Id>
</Ids>

и назначить ее в табличную переменную;

DECLARE @IdsToSearch table(id int);
INSERT INTO @IdsToSearch (id)
SELECT Ids.Id.value('.','INT') FROM @xml.nodes('/Ids/Id') as Ids(Id)

, а затем ее можно использовать вваш sql;

SELECT @nDBNum = Num
    FROM Num_members
GROUP BY Num
  HAVING SUM(CASE WHEN Part_No IN (SELECT id FROM @IdsToSearch) THEN 1 ELSE 0 END) = @nCount
     AND COUNT(*) = @nCount

Предполагается, что вы используете Sql Server 2005/2008

0 голосов
/ 30 июня 2011

Вы можете взять вашу входную строку и вызвать табличную функцию, чтобы преобразовать ее в таблицу с одним столбцом, которую вы можете вложить в предложение IN. Лучше, чем использовать динамический sql.

CREATE FUNCTION [dbo].[ConvertCSVToTable] ( @StringInput VARCHAR(8000) )
RETURNS @OutputTable TABLE ( Id int )
AS
BEGIN

    DECLARE @String    VARCHAR(10)

    WHILE LEN(@StringInput) > 0
    BEGIN
        SET @String      = LEFT(@StringInput, 
                                ISNULL(NULLIF(CHARINDEX(',', @StringInput) - 1, -1),
                                LEN(@StringInput)))
        SET @StringInput = SUBSTRING(@StringInput,
                                     ISNULL(NULLIF(CHARINDEX(',', @StringInput), 0),
                                     LEN(@StringInput)) + 1, LEN(@StringInput))

        INSERT INTO @OutputTable ( Id )
        VALUES ( @String )
    END

    RETURN
END

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

    SELECT @nDBNum = Num    FROM Num_membersGROUP BY Num  
    HAVING SUM(CASE WHEN Part_No IN (
SELECT Id from dbo.ConvertCSVToTable(@strOrderedString)
) 
    THEN 1 ELSE 0 END) = @nCount
    AND COUNT(*) = @nCount
...