while transact tabla recorrer open from fetch_status sql sql-server tsql cursor table-variable

transact - sql open



¿Puedo recorrer una variable de tabla en T-SQL? (10)

Agregue una identidad a su variable de tabla, y haga un bucle fácil de 1 a @@ ROWCOUNT de INSERT-SELECT.

Prueba esto:

DECLARE @RowsToProcess int DECLARE @CurrentRow int DECLARE @SelectCol1 int DECLARE @table1 TABLE (RowID int not null primary key identity(1,1), col1 int ) INSERT into @table1 (col1) SELECT col1 FROM table2 SET @RowsToProcess=@@ROWCOUNT SET @CurrentRow=0 WHILE @CurrentRow<@RowsToProcess BEGIN SET @CurrentRow=@CurrentRow+1 SELECT @SelectCol1=col1 FROM @table1 WHERE RowID=@CurrentRow --do your thing here-- END

¿Hay alguna forma de recorrer una variable de tabla en T-SQL?

DECLARE @table1 TABLE ( col1 int ) INSERT into @table1 SELECT col1 FROM table2

También uso cursores, pero los cursores parecen menos flexibles que las variables de tabla.

DECLARE cursor1 CURSOR FOR SELECT col1 FROM table2 OPEN cursor1 FETCH NEXT FROM cursor1

Me gustaría poder usar una variable de tabla de la misma manera que un cursor. De esa manera podría ejecutar alguna consulta sobre la variable de la tabla en una parte del procedimiento, y luego ejecutar algún código para cada fila en la variable de la tabla.

Cualquier ayuda es muy apreciada.


Aquí está mi variante. Casi como todos los demás, pero solo uso una variable para administrar el bucle.

DECLARE @LoopId int ,@MyData varchar(100) DECLARE @CheckThese TABLE ( LoopId int not null identity(1,1) ,MyData varchar(100) not null ) INSERT @CheckThese (YourData) select MyData from MyTable order by DoesItMatter SET @LoopId = @@rowcount WHILE @LoopId > 0 BEGIN SELECT @MyData = MyData from @CheckThese where LoopId = @LoopId -- Do whatever SET @LoopId = @LoopId - 1 END

El punto de Raj More es relevante, solo realice bucles si es necesario.


Aquí está mi versión de la misma solución ...

declare @id int SELECT @id = min(fPat.PatientID) FROM tbPatients fPat WHERE (fPat.InsNotes is not null AND DataLength(fPat.InsNotes)>0) while @id is not null begin SELECT fPat.PatientID, fPat.InsNotes FROM tbPatients fPat WHERE (fPat.InsNotes is not null AND DataLength(fPat.InsNotes)>0) AND fPat.PatientID=@id SELECT @id = min(fPat.PatientID) FROM tbPatients fPat WHERE (fPat.InsNotes is not null AND DataLength(fPat.InsNotes)>0)AND fPat.PatientID>@id end


Aquí hay otra respuesta, similar a la de Justin, pero no necesita una identidad o agregado, solo una clave primaria (única).

declare @table1 table(dataKey int, dataCol1 varchar(20), dataCol2 datetime) declare @dataKey int while exists select ''x'' from @table1 begin select top 1 @dataKey = dataKey from @table1 order by /*whatever you want:*/ dataCol2 desc -- do processing delete from @table1 where dataKey = @dataKey end


Mis dos centavos. De la respuesta de KM., Si quiere soltar una variable, puede hacer una cuenta atrás en @RowsToProcess en lugar de contar.

DECLARE @RowsToProcess int; DECLARE @table1 TABLE (RowID int not null primary key identity(1,1), col1 int ) INSERT into @table1 (col1) SELECT col1 FROM table2 SET @RowsToProcess = @@ROWCOUNT WHILE @RowsToProcess > 0 -- Countdown BEGIN SELECT * FROM @table1 WHERE RowID=@RowsToProcess --do your thing here-- SET @RowsToProcess = @RowsToProcess - 1; -- Countdown END


No sabía acerca de la estructura WHILE.

La estructura WHILE con una variable de tabla, sin embargo, se ve similar a usar un CURSOR, en el sentido de que todavía tiene que SELECCIONAR la fila en una variable basada en la fila IDENTITY, que es efectivamente un FETCH.

¿Hay alguna diferencia entre usar WHERE y algo como lo siguiente?

DECLARE @table1 TABLE ( col1 int ) INSERT into @table1 SELECT col1 FROM table2 DECLARE cursor1 CURSOR FOR @table1 OPEN cursor1 FETCH NEXT FROM cursor1

No sé si eso es posible. Supongo que deberías hacer esto:

DECLARE cursor1 CURSOR FOR SELECT col1 FROM @table1 OPEN cursor1 FETCH NEXT FROM cursor1

¡Gracias por tu ayuda!


Puede recorrer la variable de la tabla o puede desplazar el cursor por ella. Esto es lo que generalmente llamamos RBAR: pronunciado Reebar y significa Fila por Agonización.

Sugeriría encontrar una respuesta BASADA EN EL CONJUNTO a su pregunta (podemos ayudar con eso) y alejarnos de las rbars tanto como sea posible.


Siguiendo el ciclo de Procedimiento almacenado recorre la Variable de tabla y lo imprime en orden ascendente. Este ejemplo usa WHILE LOOP.

CREATE PROCEDURE PrintSequenceSeries -- Add the parameters for the stored procedure here @ComaSeperatedSequenceSeries nVarchar(MAX) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; DECLARE @SERIES_COUNT AS INTEGER SELECT @SERIES_COUNT = COUNT(*) FROM PARSE_COMMA_DELIMITED_INTEGER(@ComaSeperatedSequenceSeries, '','') --- ORDER BY ITEM DESC DECLARE @CURR_COUNT AS INTEGER SET @CURR_COUNT = 1 DECLARE @SQL AS NVARCHAR(MAX) WHILE @CURR_COUNT <= @SERIES_COUNT BEGIN SET @SQL = ''SELECT TOP 1 T.* FROM '' + ''(SELECT TOP '' + CONVERT(VARCHAR(20), @CURR_COUNT) + '' * FROM PARSE_COMMA_DELIMITED_INTEGER( '''''' + @ComaSeperatedSequenceSeries + '''''' , '''','''') ORDER BY ITEM ASC) AS T '' + ''ORDER BY T.ITEM DESC '' PRINT @SQL EXEC SP_EXECUTESQL @SQL SET @CURR_COUNT = @CURR_COUNT + 1 END;

La siguiente declaración ejecuta el procedimiento almacenado:

EXEC PrintSequenceSeries ''11,2,33,14,5,60,17,98,9,10''

El resultado que se muestra en la ventana de consulta SQL se muestra a continuación:

La función PARSE_COMMA_DELIMITED_INTEGER () que devuelve la variable TABLE es la siguiente:

CREATE FUNCTION [dbo].[parse_comma_delimited_integer] ( @LIST VARCHAR(8000), @DELIMITER VARCHAR(10) = '', '' ) -- TABLE VARIABLE THAT WILL CONTAIN VALUES RETURNS @TABLEVALUES TABLE ( ITEM INT ) AS BEGIN DECLARE @ITEM VARCHAR(255) /* LOOP OVER THE COMMADELIMITED LIST */ WHILE (DATALENGTH(@LIST) > 0) BEGIN IF CHARINDEX(@DELIMITER,@LIST) > 0 BEGIN SELECT @ITEM = SUBSTRING(@LIST,1,(CHARINDEX(@DELIMITER, @LIST)-1)) SELECT @LIST = SUBSTRING(@LIST,(CHARINDEX(@DELIMITER, @LIST) + DATALENGTH(@DELIMITER)),DATALENGTH(@LIST)) END ELSE BEGIN SELECT @ITEM = @LIST SELECT @LIST = NULL END -- INSERT EACH ITEM INTO TEMP TABLE INSERT @TABLEVALUES ( ITEM ) SELECT ITEM = CONVERT(INT, @ITEM) END RETURN END


mira como esta demostración:

DECLARE @vTable TABLE (IdRow int not null primary key identity(1,1),ValueRow int); -------Initialize--------- insert into @vTable select 345; insert into @vTable select 795; insert into @vTable select 565; --------------------------- DECLARE @cnt int = 1; DECLARE @max int = (SELECT MAX(IdRow) FROM @vTable); WHILE @cnt <= @max BEGIN DECLARE @tempValueRow int = (Select ValueRow FROM @vTable WHERE IdRow = @cnt); ---work demo---- print ''@tempValueRow:'' + convert(varchar(10),@tempValueRow); print ''@cnt:'' + convert(varchar(10),@cnt); print''''; -------------- set @cnt = @cnt+1; END

Versión sin idRow, usando ROW_NUMBER

DECLARE @vTable TABLE (ValueRow int); -------Initialize--------- insert into @vTable select 345; insert into @vTable select 795; insert into @vTable select 565; --------------------------- DECLARE @cnt int = 1; DECLARE @max int = (select count(*) from @vTable); WHILE @cnt <= @max BEGIN DECLARE @tempValueRow int = ( select ValueRow from (select ValueRow , ROW_NUMBER() OVER(ORDER BY (select 1)) as RowId from @vTable ) T1 where t1.RowId = @cnt ); ---work demo---- print ''@tempValueRow:'' + convert(varchar(10),@tempValueRow); print ''@cnt:'' + convert(varchar(10),@cnt); print''''; -------------- set @cnt = @cnt+1; END


DECLARE @table1 TABLE ( idx int identity(1,1), col1 int ) DECLARE @counter int SET @counter = 1 WHILE(@counter < SELECT MAX(idx) FROM @table1) BEGIN DECLARE @colVar INT SELECT @colVar = col1 FROM @table1 WHERE idx = @counter -- Do your work here SET @counter = @counter + 1 END

Lo creas o no, esto es en realidad más eficiente y eficiente que usar un cursor.