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.