Может ли хранимая процедура использовать динамические параметры в предложении "IN"?
Я хочу запустить такой запрос:
SELECT * FROM Studio WHERE Id IN (134, 144, 132, 138, 7432, 7543, 2566)
но количество Id, переданное в предложение IN, определяется только во время выполнения.
Нужно ли использовать динамический SQL или это можно сделать с помощью хранимой процедуры?
UPDATE:
Если доступна какая-либо опция, какая из них лучше?
Спасибо.
Ответы
Ответ 1
В зависимости от вашей версии Sql Server вы можете сделать это одним из двух способов.
В Sql 2000/2005 вы можете использовать параметр (тип varchar), который имеет разграниченный список идентификаторов. Создайте UDF, который будет анализировать varchar и возвращать таблицу, содержащую элементы. Затем сделайте свой пункт IN против таблицы (то есть... IN (выберите ID FROM @ReturnTable)).
Вот пример того, как будет выглядеть содержимое UDF:
http://pietschsoft.com/post/2006/02/03/T-SQL-Parse-a-delimited-string.aspx
Для Sql 2008 вы можете сделать то же самое; однако вместо того, чтобы передавать параметр varchar, вы можете просто перерезать преследование и передать параметр таблицы. Предложение IN все равно будет иметь подзапрос, но все равно будет работать. В качестве альтернативы, как только у вас есть таблица, вы можете просто сделать Inner Join на ней и обойти необходимость в разделе IN.
EDIT: добавлен UDF для разбора строковой ссылки с разделителями.
Ответ 2
Решение, описанное здесь:
Массивы и списки в SQL Server 2005
Текст SQL от Erland Sommarskog, SQL Server MVP
http://www.sommarskog.se/arrays-in-sql-2005.html
Ответ 3
Это можно сделать в хранимой процедуре.
создать временную таблицу внутри хранимой процедуры и вставить значения, разделенные запятыми или любым разделителем, тогда сделайте это
SELECT * FROM Studio WHERE Id IN (select id from temptable)
Затем удалите таблицу.
Ответ 4
Вот UDF, который я использую с MSSQL 2000. Я нашел это где-то - извините, не могу вспомнить где.
В принципе, вы можете сделать соединение в UDF, где первый параметр является разделительной строкой, а второй параметр - разделителем.
SELECT 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
Ответ 5
В SQL 2008 вы можете использовать параметр table value.
В SQL 2005 вы должны использовать динамический SQL, если вы не хотите передавать этот список как XML и использовать обработку XML в процедуре, чтобы отбросить XML обратно в переменную таблицы.
Ответ 6
объявить таблицу @temp и разбить в нее значения. то вы могли бы сделать
выберите * из внутреннего соединения Studio
@temptable tb
на s.ID = tb.ID