sourcecode

T-SQL에서 테이블 변수를 루프할 수 있습니까?

codebag 2023. 6. 22. 21:49
반응형

T-SQL에서 테이블 변수를 루프할 수 있습니까?

T-SQL에서 테이블 변수를 루프할 수 있는 방법이 있습니까?

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

커서도 사용하지만 커서는 테이블 변수보다 유연하지 않은 것 같습니다.

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

테이블 변수를 커서와 같은 방식으로 사용할 수 있으면 좋겠습니다.그러면 절차의 한 부분에서 테이블 변수에 대한 쿼리를 실행하고 나중에 테이블 변수의 각 행에 대한 코드를 실행할 수 있습니다.

어떤 도움이든 대단히 감사합니다.

테이블 변수에 아이덴티티를 추가하고 INSERT-SELECT의 @@ROWCOUNT까지 1에서 쉬운 루프를 수행합니다.

사용해 보십시오.

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
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

믿거나 말거나, 이것은 실제로 커서를 사용하는 것보다 더 효율적이고 성능이 좋습니다.

내 2센트..KM.의 답변에 따르면 변수 하나를 삭제하려면 카운트업 대신 @RowsToProcess에서 카운트다운을 수행할 수 있습니다.

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

테이블 변수를 순환하거나 커서로 이동할 수 있습니다.이것은 우리가 보통 RBAR라고 부르는 것입니다 - Reebar로 발음되고 Row-by-Agonizing-Row를 의미합니다.

저는 당신의 질문에 대한 SET 기반 답변을 찾고 가능한 한 rbar에서 벗어나길 제안합니다.

이 데모처럼 보입니다.

DECLARE @Table TABLE (IdRow int not null identity(1,1), MyValue int);
insert into @Table select 345;
insert into @Table select 795;
insert into @Table select 565;

DECLARE @i int = 1;
DECLARE @rows int = (SELECT MAX(IdRow) FROM @Table);

WHILE @i <= @rows
BEGIN
    DECLARE @MyValue int = (Select top 1 MyValue FROM @Table WHERE IdRow = @i);

    print Concat('@i:', @i, ' ', '@MyValue:', @MyValue);

    set @i = @i + 1;
END

idRow가 없는 버전, ROW_NUMBER 사용

DECLARE @Table TABLE (IdRow int not null identity(1,1), MyValue int);
insert into @Table select 345;
insert into @Table select 795;
insert into @Table select 565;

DECLARE @i int = 1;
DECLARE @max int = (select count(*) from @Table);

WHILE @i <= @max
BEGIN
    DECLARE @MyValue int = (

        select T1.MyValue 
        from (
            select MyValue, 
            ROW_NUMBER() OVER(ORDER BY (select 1)) as RowId 
            from @Table
        ) T1 
        where T1.RowId = @i
    );

    print Concat('@i:', @i, ' ', '@MyValue:', @MyValue);

    set @i = @i+1;
END

Justin의 답변과 유사하지만 ID나 집계가 필요하지 않고 기본(고유한) 키만 필요한 다른 답변이 있습니다.

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

여기 제 변종이 있습니다.다른 모든 것들과 거의 비슷하지만, 저는 루프를 관리하기 위해 하나의 변수만 사용합니다.

DECLARE
  @LoopId  int
 ,@MyData  varchar(100)

DECLARE @CheckThese TABLE
 (
   LoopId  int  not null  identity(1,1)
  ,MyData  varchar(100)  not null
 )


INSERT @CheckThese (MyData)
 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

Raj More의 요점은 관련이 있습니다. 필요한 경우에만 루프를 수행합니다.

저는 WHEN 구조에 대해 몰랐습니다.

그러나 테이블 변수가 있는 WHIN 구조는 행 ID에 따라 변수로 행을 선택해야 한다는 점에서 커서를 사용하는 것과 유사하며, 이는 사실상 FETCH입니다.

WHERE를 사용하는 것과 다음과 같은 것과 다른 점이 있습니까?

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

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

그게 가능할지도 모르겠어요다음과 같이 해야 할 것 같습니다.

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

도와주셔서 감사합니다!

여기 제 버전의 동일한 솔루션이 있습니다.

    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

저장 프로시저를 따라 표 변수를 루프하여 오름차순으로 인쇄합니다.이 예는 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;

다음 문은 저장 프로시저를 실행합니다.

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

SQL 쿼리 창에 표시되는 결과는 다음과 같습니다.

The Result of PrintSequenceSeries

TABLE 변수를 반환하는 PARSE_COMMA_DELIMITED_INTEGER() 함수는 다음과 같습니다.

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

Top 1을 선택하면 시퀀스/순서 없이 쉽게 해결할 수 있습니다.

Create Function Test_Range()
Returns
@Result Table (ID Int)
As
Begin

Declare @ID Varchar(10) = ''
Declare @Rows Int, @Row Int = 0
Declare @Num Int, @RangeTo Int

Declare @RangeTable Table (ID Varchar(10), RangeFrom Int, RangeTo Int)
Insert Into @RangeTable Values ('A', 1, 10)
Insert Into @RangeTable Values ('B', 25,30)

Set @Rows = (Select Count(*) From @RangeTable)

While @Row <= @Rows
Begin
    Set @Row = @Row + 1
    Select Top 1 @ID = ID, @Num = RangeFrom, @RangeTo = RangeTo  From @RangeTable
    Where ID > @ID
    While @Num <= @RangeTo
    Begin
        Insert Into @Result Values (@Num)
        Set @Num = @Num + 1
    End
End
Return
End

언급URL : https://stackoverflow.com/questions/1578198/can-i-loop-through-a-table-variable-in-t-sql

반응형