2009-06-10 17 views
6

Quiero ejecutar una consulta como esta:¿Puede un procedimiento almacenado tener parámetros dinámicos para ser utilizado en una cláusula "IN"?

SELECT * FROM Studio WHERE Id IN (134, 144, 132, 138, 7432, 7543, 2566) 

pero la cantidad de Id 's se pasan a la cláusula IN se determina sólo en tiempo de ejecución.

¿Tengo que usar SQL dinámico o se puede hacer esto con un procedimiento almacenado?

ACTUALIZACIÓN: Si hay alguna opción disponible, ¿cuál es mejor?

Gracias.

+0

son Identificación del generada por la entrada del usuario? – Eric

+0

El usuario selecciona los registros para buscar con una casilla de verificación pero no tiene control sobre cuál es el "Id" real. – orandov

+0

Entonces sql dinámico no es una mala idea si no está sujeto a inyección ... pero pruebe la respuesta que publiqué en su lugar para estar seguro. – Eric

Respuesta

8

Dependiendo de la versión de SQL Server, puedes hacer esto de dos maneras diferentes.

Para Sql 2000/2005, puede usar un parámetro (tipo varchar) que tenga una lista delimitada de ID. Cree una UDF que analizaría el varchar y devolvería una tabla que contiene los elementos. Luego, haga que su cláusula IN vaya contra la tabla (es decir, ... IN (Seleccione ID FROM @ReturnTable)).

He aquí un ejemplo de lo que el contenido de la UDF se vería así: http://pietschsoft.com/post/2006/02/03/T-SQL-Parse-a-delimited-string.aspx

para SQL 2008, puede hacer lo mismo; sin embargo, en lugar de pasar un parámetro varchar puedes simplemente cortar al chase y pasar un parámetro de tabla. La cláusula IN aún tendría una subconsulta pero funcionaría de todos modos. Alternativamente, una vez que tenga la tabla, puede hacer una combinación interna y evitar la necesidad de la cláusula IN.

EDITAR: se agregó UDF para analizar un enlace de cadena delimitado.

+0

Como su enlace ya no funciona, voy a compartir este que sí: http://jerrytech.blogspot.com/2008/04/no-split-in-sql-well-here-method-you .html –

0

En SQL 2008 puede usar table valued parameter.

En SQL 2005 debe usar SQL dinámico a menos que desee pasar la lista como XML y usar el procesamiento XML en el procedimiento para triturar el XML en una variable de tabla.

+0

No necesita SQL dinámico para analizar una lista delimitada. Vea la página de Erland Sommarskog, como lo menciona Alex. –

+0

Hola Remus, No estoy de acuerdo. Trabajo en 2005, guardo los números en una imagen y los analizo usando un UDF: http://www.sommarskog.se/arrays-in-sql-2005.html –

+0

cierto, reconozco que el procesamiento de cadenas es una alternativa viable y debería haberlo mencionado. Publicación privada de café :) –

0

declare una tabla @temp y divida los valores en ella. entonces usted podría hacer

seleccionar * de Estudio s combinación interna tb @temptable en s.ID = tb.ID

3

Puede hacer absolutamente esto en un procedimiento almacenado.

crear una tabla temporal dentro del procedimiento almacenado e insertar los valores divididos sobre las comas o cualquier delimitador luego hacer esto

SELECT * FROM Studio WHERE Id IN (select id from temptable) 

continuación, elimine la tabla.

+0

Esta es posiblemente la mejor solución porque nunca se sabe la cantidad de datos malolientes que está pasando en ese procedimiento almacenado. Puede mejorar significativamente el rendimiento usando una tabla temporal así si la cantidad es alta. –

1

Aquí hay una UDF que he estado usando desde MSSQL 2000. Encontré esto en alguna parte, lo siento, no puedo recordar dónde.

Básicamente, puede hacer una unión en la UDF, donde el primer parámetro es la cadena delimitada, y el segundo parámetro es el delimitador.

t1.somecolumn SELECT FROM t1 sometable INNER JOIN dbo.Split (@delimitedVar, '') t2 EN 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 
Cuestiones relacionadas