Pregunta

¿Existe una manera elegante de manejar el paso de una lista de identificadores como parámetro a un procedimiento almacenado?

Por ejemplo, quiero que mi procedimiento almacenado devuelva los departamentos 1, 2, 5, 7, 20.En el pasado, pasé una lista de identificadores delimitados por comas, como el siguiente código, pero me siento muy sucio al hacerlo.

Creo que SQL Server 2005 es mi única limitación aplicable.

create procedure getDepartments
  @DepartmentIds varchar(max)
as
  declare @Sql varchar(max)     
  select @Sql = 'select [Name] from Department where DepartmentId in (' + @DepartmentIds + ')'
  exec(@Sql)
¿Fue útil?

Solución

Erland Sommarskog mantiene desde hace 16 años la respuesta autorizada a esta pregunta: Matrices y listas en SQL Server.

Hay al menos una docena de formas de pasar una matriz o lista a una consulta;cada uno tiene sus propios pros y contras.

Realmente no puedo recomendar lo suficiente para leer el artículo para conocer las ventajas y desventajas entre todas estas opciones.

Otros consejos

Sí, su solución actual es propensa a ataques de inyección SQL.

La mejor solución que he encontrado es usar una función que divide el texto en palabras (hay algunas publicadas aquí, o puedes usar este de mi blog) y luego únelo a tu mesa.Algo como:

SELECT d.[Name]
FROM Department d
    JOIN dbo.SplitWords(@DepartmentIds) w ON w.Value = d.DepartmentId

Podrías usar XML.

P.ej.

declare @xmlstring as  varchar(100) 
set @xmlstring = '<args><arg value="42" /><arg2>-1</arg2></args>' 

declare @docid int 

exec sp_xml_preparedocument @docid output, @xmlstring

select  [id],parentid,nodetype,localname,[text]
from    openxml(@docid, '/args', 1) 

El comando sp_xml_preparedocument está integrado.

Esto produciría la salida:

id  parentid    nodetype    localname   text
0   NULL        1           args        NULL
2   0           1           arg         NULL
3   2           2           value       NULL
5   3           3           #text       42
4   0           1           arg2        NULL
6   4           3           #text       -1

que tiene todo (¿más?) lo que necesitas.

Un método que quizás quieras considerar si vas a trabajar mucho con los valores es escribirlos primero en una tabla temporal.Luego simplemente únete como de costumbre.

De esta manera, solo estarás analizando una vez.

Es más fácil usar una de las UDF 'divididas', pero tanta gente ha publicado ejemplos de ellas que pensé en tomar una ruta diferente;)

Este ejemplo creará una tabla temporal a la que puede unirse (#tmpDept) y la completará con la identificación del departamento que ingresó.Supongo que los estás separando con comas, pero puedes, por supuesto, cambiarlo a lo que quieras.

IF OBJECT_ID('tempdb..#tmpDept', 'U') IS NOT NULL
BEGIN
    DROP TABLE #tmpDept
END

SET @DepartmentIDs=REPLACE(@DepartmentIDs,' ','')

CREATE TABLE #tmpDept (DeptID INT)
DECLARE @DeptID INT
IF IsNumeric(@DepartmentIDs)=1
BEGIN
    SET @DeptID=@DepartmentIDs
    INSERT INTO #tmpDept (DeptID) SELECT @DeptID
END
ELSE
BEGIN
        WHILE CHARINDEX(',',@DepartmentIDs)>0
        BEGIN
            SET @DeptID=LEFT(@DepartmentIDs,CHARINDEX(',',@DepartmentIDs)-1)
            SET @DepartmentIDs=RIGHT(@DepartmentIDs,LEN(@DepartmentIDs)-CHARINDEX(',',@DepartmentIDs))
            INSERT INTO #tmpDept (DeptID) SELECT @DeptID
        END
END

Esto le permitirá pasar una identificación de departamento, varias identificaciones con comas entre ellas o incluso varias identificaciones con comas y espacios entre ellas.

Entonces, si hicieras algo como:

SELECT Dept.Name 
FROM Departments 
JOIN #tmpDept ON Departments.DepartmentID=#tmpDept.DeptID
ORDER BY Dept.Name

Verá los nombres de todos los ID de departamento que pasó...

Nuevamente, esto se puede simplificar usando una función para llenar la tabla temporal...Principalmente lo hice sin uno solo para matar el aburrimiento :-P

--Kevin Fairchild

Un método XML ultrarrápido, si desea utilizar un procedimiento almacenado y pasar la lista de ID de departamento separados por comas:

Declare @XMLList xml
SET @XMLList=cast('<i>'+replace(@DepartmentIDs,',','</i><i>')+'</i>' as xml)
SELECT x.i.value('.','varchar(5)') from @XMLList.nodes('i') x(i))

Todo el crédito es para Guru. Blog de Brad Schulz

Pruebe este:

@list_of_params varchar(20) -- value 1, 2, 5, 7, 20 

SELECT d.[Name]
FROM Department d
where @list_of_params like ('%'+ CONVERT(VARCHAR(10),d.Id)  +'%')

muy simple.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top