Um procedimento armazenado pode ter parâmetros dinâmicos a serem usados em uma cláusula "in"?
-
13-09-2019 - |
Pergunta
Eu quero executar uma consulta como esta:
SELECT * FROM Studio WHERE Id IN (134, 144, 132, 138, 7432, 7543, 2566)
Mas a quantidade de IdentidadePassado para a cláusula IN é determinado apenas em tempo de execução.
Eu tenho que usar o SQL dinâmico ou isso pode ser feito com um procedimento armazenado?
ATUALIZAR:Se qualquer uma das opções estiver disponível, qual é melhor?
Obrigado.
Solução
Dependendo da sua versão do SQL Server, você pode fazer essa de duas maneiras diferentes.
Para o SQL 2000/2005, você pode usar um parâmetro (tipo VARCHAR) que possui uma lista delimitada de IDs. Crie um UDF que analisasse o Varchar e retorne uma tabela que contém os itens. Em seguida, faça sua cláusula no IN vá contra a tabela (ou seja ... em (selecione ID de @RETURNTABLE)).
Aqui está um exemplo de como seria o conteúdo da UDF:http://pietschsoft.com/post/2006/02/03/t-sql-parse-delimited-string.aspx
Para o SQL 2008, você pode fazer a mesma coisa; No entanto, em vez de passar em um parâmetro VARCHAR, você pode simplesmente cortar para a perseguição e passar em um parâmetro de tabela. A cláusula in ainda teria uma subconsulta, mas funcionaria da mesma forma. Como alternativa, depois de ter a tabela, você pode simplesmente fazer uma junção interna e contornar a necessidade da cláusula In.
Editar: Adicionado UDF para analisar um link de string delimitado.
Outras dicas
Solução descrita aqui:
Matrizes e listas no SQL Server 2005
Um texto SQL de Erland Sommarskog, SQL Server MVP
Você pode absolutamente fazer isso em um procedimento armazenado.
Crie uma tabela de temperatura dentro do procedimento armazenado e insira os valores divididos nas vírgulas ou em qualquer delimitador, faça isso
SELECT * FROM Studio WHERE Id IN (select id from temptable)
Em seguida, exclua a tabela.
Aqui está um UDF que eu uso desde o MSSQL 2000. Encontrei isso em algum lugar - desculpe, não me lembro onde.
Basicamente, você pode fazer uma junção no UDF, onde o primeiro parâmetro é a sequência delimitada, e o segundo param é o delimitador.
Selecione T1.Somecolumn de algum consumo interno T1 DBO.SPLIT (@DelimitedVar, ',') T2 em 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
No SQL 2008, você pode usar um Tabela Parâmetro avaliado.
No SQL 2005, você deve usar o SQL dinâmico, a menos que queira passar a lista como XML e usar o processamento XML no procedimento para destruir o XML em uma variável de tabela.
Declare uma tabela @temp e divida os valores nela. Então você poderia fazer
Selecione * do Studio S Inner Junção @temptable TB em s.id = tb.id