2011-07-07 16 views
19

Considere el cuadro de muestra:iterar a través de filas en SQL Server 2008

id  integer 
name  nvarchar(10) 

No es un procedimiento almacenado llamado myproc. Sólo se necesita una parámetro de (que es id)

Dado un nombre como parámetro, encontrar todas las filas con el name = @nameparameter y pasar todos esos ids a myproc

por ejemplo:

sample-> 
1 mark 
2 mark 
3 stu 
41 mark 

Cuando mark es pasado, 1 ,2 and 41 se pasan a myproc individualmente.

es decir, el siguiente debería ocurrir:

execute myproc 1 
execute myproc 2 
execute myproc 41 

no puede tocar ni myproc ver su contenido. Solo tengo que pasarle los valores.

+7

Aunque esto * se puede * hacer, lo mejor es generalmente evitarlo, generalmente convirtiendo el proceso almacenado en una UDF, o expandiéndolo en línea, para que se pueda realizar una operación basada en el conjunto.Tendríamos que ver las partes internas de 'myproc' para asesorar qué enfoque era factible en este caso. En SQL, debe * generalmente * buscar soluciones basadas en conjuntos para problemas, no basados ​​en bucles. –

+0

Simialr Pregunta aquí respondida http://stackoverflow.com/questions/20662356/sql-server-loop-how-do-i-loop-through-a-set-of-records/34797745#34797745 – Sandeep

+1

@Sandeep, esto es una pregunta anterior y acepté la solución – psy

Respuesta

42

Si necesidad iterate (*), utiliza el constructo diseñado para hacerlo - el cursor. Vilipendiado, pero si se expresa con mayor claridad sus intenciones, digo usarlo:

DECLARE @ID int 
DECLARE IDs CURSOR LOCAL FOR select ID from SAMPLE where Name = @NameParameter 

OPEN IDs 
FETCH NEXT FROM IDs into @ID 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    exec myproc @ID 

    FETCH NEXT FROM IDs into @ID 
END 

CLOSE IDs 
DEALLOCATE IDs 

(*) Esta respuesta ha recibido algunas upvotes hace poco, pero siento que debo incorporar mi comentario original aquí también, y agregue algunos consejos generales:

En SQL, debe generalmente buscar una solución basada en conjuntos. Todo el lenguaje está orientado a soluciones basadas en conjuntos, y (a su vez) el optimizador está orientado a hacer que las soluciones basadas en conjuntos funcionen bien. A su vez, las herramientas que tenemos disponibles para la optimización el optimizador también están orientadas a conjuntos, p. aplicando índices a las tablas.

Hay algunas situaciones donde la iteración es el mejor enfoque. Estos son pocos y se pueden comparar con las reglas de optimización de Jackson, no lo haga, y (para los expertos solamente) no lo haga pero.

Es mucho mejor que primero intente formular lo que quiere en términos del conjunto de todas las filas que se verán afectadas: ¿cuál es el cambio general que se logrará? - y luego intenta formular una consulta que encapsula ese objetivo. Solo si la consulta producida al hacerlo no funciona adecuadamente (o hay algún otro componente que no puede hacer otra cosa que tratar con cada fila individualmente) debe considerar la iteración.

+0

Quiero utilizar un cursor para enviar dbmail a los destinatarios, que están definidos por una consulta establecida, uno a la vez, de modo que pueda detectar fallas. Según su segunda parte de su respuesta, ¿sería este un uso adecuado? – DFTR

+1

@DFTR - podría serlo - siempre que tenga en cuenta que no podrá detectar todas las fallas posibles en esta etapa - la entrega de correo electrónico no está garantizada, incluso si todo funciona bien en el lado de SQL Server. –

+0

Sí, pensé en eso. Pero al menos sabré que llegó a nuestros sophos, que es básicamente donde termina mi trabajo. Entonces ... gana. – DFTR

-3
Declare @retStr varchar(100) 

select @retStr = COALESCE(@retStr, '') + sample.ID + ', ' 
from sample 
WHERE sample.Name = @nameparameter 
select @retStr = ltrim(rtrim(substring(@retStr , 1, len(@retStr)- 1))) 

Return ISNULL(@retStr ,'') 
6

simplemente declaro la @sample tabla temporal e inserte el que todas las filas que tienen el nombre = 'Rahul' y también tener la columna de estado para comprobar que la fila está utilizando iterated.and bucle while i iterar a través de la todas las filas de la tabla temporal @sample que tienen todos los identificadores de nombre = 'Rahul'

use dumme 

Declare @Name nvarchar(50) 
set @Name='Rahul' 
DECLARE @sample table (

    ID int, 
    Status varchar(500) 

    ) 
insert into @sample (ID,status) select ID,0 from sample where [email protected] 
while ((select count(Id) from @sample where status=0)>0) 
begin 
    select top 1 Id from @sample where status=0 order by Id 
    update @sample set status=1 where Id=(select top 1 Id from @sample where status=0 order by Id) 
end 
+0

Puede declarar ID como Identidad (1,1) y recorrerlo sin tener que actualizarlo. –