Может ли хранимая процедура иметь динамические параметры для использования в предложении «IN»?
-
13-09-2019 - |
Вопрос
Я хочу запустить такой запрос:
SELECT * FROM Studio WHERE Id IN (134, 144, 132, 138, 7432, 7543, 2566)
но количество Идентификаторпереданные в предложение IN, определяются только во время выполнения.
Нужно ли использовать динамический SQL или это можно сделать с помощью хранимой процедуры?
ОБНОВЛЯТЬ:Если доступен любой из вариантов, какой из них лучше?
Спасибо.
Решение
В зависимости от вашей версии Sql Server вы можете сделать это одним из двух способов.
Для Sql 2000/2005 вы можете использовать параметр (типа varchar), который имеет разделенный список идентификаторов.Создайте UDF, который будет анализировать varchar и возвращать таблицу, содержащую элементы.Затем сделайте предложение IN сопоставленным с таблицей (т....IN (выберите идентификатор из @ReturnTable)).
Вот пример того, как будет выглядеть содержимое UDF:http://pietschsoft.com/post/2006/02/03/T-SQL-Parse-a-delimited-string.aspx
Для Sql 2008 вы можете сделать то же самое;однако вместо передачи параметра varchar вы можете просто перейти к делу и передать параметр таблицы.Предложение IN по-прежнему будет иметь подзапрос, но оно все равно будет работать.В качестве альтернативы, когда у вас есть таблица, вы можете просто выполнить для нее внутреннее соединение и обойти необходимость в предложении IN.
РЕДАКТИРОВАТЬ:добавлен UDF для анализа ссылки на строку с разделителями.
Другие советы
Решение описано здесь:
Массивы и списки в SQL Server 2005
Текст по SQL, написанный Эрландом Соммарскогом, MVP по SQL Server.
Вы можете сделать это в хранимой процедуре.
создайте временную таблицу внутри хранимой процедуры и вставьте значения, разделенные запятыми или любым разделителем, затем сделайте это
SELECT * FROM Studio WHERE Id IN (select id from temptable)
Затем удалите таблицу.
Вот UDF, который я использую с MSSQL 2000.Я где-то это нашел, извините, не помню где.
По сути, вы можете выполнить соединение с UDF, где первый параметр — это строка с разделителями, а второй параметр — разделитель.
ВЫБРАТЬ t1.somecolumn FROM sometable t1 INNER JOIN dbo.Split(@delimitedVar, ',') t2 ON t1.ID = t2.Element
CREATE FUNCTION [dbo].[Split]
(
@vcDelimitedString varchar(max),
@vcDelimiter varchar(100)
)
RETURNS @tblArray TABLE
(
ElementID smallint IDENTITY(1,1), --Array index
Element varchar(1000) --Array element contents
)
AS
BEGIN
DECLARE @siIndex smallint, @siStart smallint, @siDelSize smallint
SET @siDelSize = LEN(@vcDelimiter)
--loop through source string and add elements to destination table array
WHILE LEN(@vcDelimitedString) > 0
BEGIN
SET @siIndex = CHARINDEX(@vcDelimiter, @vcDelimitedString)
IF @siIndex = 0
BEGIN
INSERT INTO @tblArray VALUES(@vcDelimitedString)
BREAK
END
ELSE
BEGIN
INSERT INTO @tblArray VALUES(SUBSTRING(@vcDelimitedString, 1,@siIndex - 1))
SET @siStart = @siIndex + @siDelSize
SET @vcDelimitedString = SUBSTRING(@vcDelimitedString, @siStart , LEN(@vcDelimitedString) - @siStart + 1)
END
END
RETURN
END
В SQL 2008 вы можете использовать табличный параметр.
В SQL 2005 вы должны использовать динамический SQL, если только вы не хотите передавать список в виде XML и использовать обработку XML в процедуре для измельчения XML обратно в табличную переменную.
объявите таблицу @temp и разделите на нее значения.тогда ты мог бы сделать
Выберите * из внутреннего соединения @temptable tb on s.id = tb.id