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
커서와 같은 방식으로 테이블 변수를 사용하고 싶습니다. 이렇게하면 프로 시저의 한 부분에서 테이블 변수에 대한 일부 쿼리를 실행 한 다음 나중에 테이블 변수의 각 행에 대해 일부 코드를 실행할 수 있습니다.
어떤 도움이라도 대단히 감사합니다.
테이블 변수에 ID를 추가하고 1부터 INSERT-SELECT의 @@ ROWCOUNT까지 쉬운 루프를 수행합니다.
이 시도:
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
믿거 나 말거나 이것은 실제로 커서를 사용하는 것보다 더 효율적이고 성능이 좋습니다.
My two cents .. 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 기반 답변을 찾고 (우리가 도울 수 있음) 가능한 한 rbars에서 벗어나십시오.
이 데모처럼 보입니다.
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
idRow가없는 버전, 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
@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의 요점은 관련성이 있습니다. 필요한 경우에만 루프를 수행하십시오.
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
WHILE 구조에 대해서는 몰랐습니다.
그러나 테이블 변수가있는 WHILE 구조는 CURSOR를 사용하는 것과 유사합니다. 실제로 FETCH 인 행 IDENTITY를 기반으로 행을 변수로 선택해야한다는 점입니다.
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 쿼리 창에 표시되는 결과는 다음과 같습니다.
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
참고URL : https://stackoverflow.com/questions/1578198/can-i-loop-through-a-table-variable-in-t-sql
'programing' 카테고리의 다른 글
"m1 = null; 실행 후 가비지 수집 대상 개체 수" (0) | 2020.11.14 |
---|---|
Postman-변수가 대체 된 헤더 및 본문 데이터가있는 요청을 보는 방법 (0) | 2020.11.14 |
댓글이 통역 언어를 느리게합니까? (0) | 2020.11.14 |
버퍼를 변경할 때 VIM에서 실행 취소 기록이 손실 됨 (0) | 2020.11.14 |
git-끌어 오기를 시도하고 혼란스러운 메시지를받는 새로운 사용자 (0) | 2020.11.14 |