SQL Server에서 Forech를 쓰는 방법
저는 각각을 위한 무언가를 달성하려고 합니다.반환된 선택문의 ID를 가져와 각각의 ID를 사용하고 싶습니다.
DECLARE @i int
DECLARE @PractitionerId int
DECLARE @numrows int
DECLARE @Practitioner TABLE (
idx smallint Primary Key IDENTITY(1,1)
, PractitionerId int
)
INSERT @Practitioner
SELECT distinct PractitionerId FROM Practitioner
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM Practitioner)
IF @numrows > 0
WHILE (@i <= (SELECT MAX(idx) FROM Practitioner))
BEGIN
SET @PractitionerId = (SELECT PractitionerId FROM @Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @PractitionerId
SET @i = @i + 1
END
현재 위와 같은 오류가 발생하고 있습니다.
열 이름 'idx'가 잘못되었습니다.
사용하시는 것 같습니다.CURSOR
대부분의 경우 세트 기반 솔루션을 사용하는 것이 가장 좋지만, 경우에 따라서는CURSOR
가장 좋은 해결책입니다.고객의 실제 문제에 대해 자세히 알지 못하면 그 이상의 도움을 드릴 수 없습니다.
DECLARE @PractitionerId int
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT DISTINCT PractitionerId
FROM Practitioner
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @PractitionerId
WHILE @@FETCH_STATUS = 0
BEGIN
--Do something with Id here
PRINT @PractitionerId
FETCH NEXT FROM MY_CURSOR INTO @PractitionerId
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
[ ActionerId ]컬럼이 고유하다고 가정하면 다음 루프를 사용할 수 있습니다.
DECLARE @PractitionerId int = 0
WHILE(1 = 1)
BEGIN
SELECT @PractitionerId = MIN(PractitionerId)
FROM dbo.Practitioner WHERE PractitionerId > @PractitionerId
IF @PractitionerId IS NULL BREAK
SELECT @PractitionerId
END
일반적으로 (거의 항상) 커서보다 성능이 뛰어나고 간단합니다.
DECLARE @PractitionerList TABLE(PracticionerID INT)
DECLARE @PracticionerID INT
INSERT @PractitionerList(PracticionerID)
SELECT PracticionerID
FROM Practitioner
WHILE(1 = 1)
BEGIN
SET @PracticionerID = NULL
SELECT TOP(1) @PracticionerID = PracticionerID
FROM @PractitionerList
IF @PracticionerID IS NULL
BREAK
PRINT 'DO STUFF'
DELETE TOP(1) FROM @PractitionerList
END
선택 카운트와 최대 선택 값은 실제 테이블이 아닌 테이블 변수에서 지정해야 합니다.
DECLARE @i int
DECLARE @PractitionerId int
DECLARE @numrows int
DECLARE @Practitioner TABLE (
idx smallint Primary Key IDENTITY(1,1)
, PractitionerId int
)
INSERT @Practitioner
SELECT distinct PractitionerId FROM Practitioner
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM @Practitioner)
IF @numrows > 0
WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
BEGIN
SET @PractitionerId = (SELECT PractitionerId FROM @Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @PractitionerId
SET @i = @i + 1
END
이 칼럼을 제외하고 모든 게 잘 될 것 같습니다.idx
선택한 테이블에 실제로 존재하지 않습니다.아마도 당신은 그 중에서 선택하라는 뜻이었을 것이다.@Practitioner
:
WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
위의 코드에 다음과 같이 정의되어 있기 때문입니다.
DECLARE @Practitioner TABLE (
idx smallint Primary Key IDENTITY(1,1)
, PractitionerId int
)
사용하시는 버전에서는 다음 행이 올바르지 않습니다.
WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
(@ 누락)
테이블이 더 달라지도록 명명 규칙을 변경하는 것이 좋습니다.
여기 더 나은 해결책 중 하나가 있습니다.
DECLARE @i int
DECLARE @curren_val int
DECLARE @numrows int
create table #Practitioner (idx int IDENTITY(1,1), PractitionerId int)
INSERT INTO #Practitioner (PractitionerId) values (10),(20),(30)
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM #Practitioner)
IF @numrows > 0
WHILE (@i <= (SELECT MAX(idx) FROM #Practitioner))
BEGIN
SET @curren_val = (SELECT PractitionerId FROM #Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @curren_val
SET @i = @i + 1
END
여기 표에 몇 가지 값을 추가했습니다.처음에는 비어 있습니다.
루프 본체에 접속하거나 루프 본체에 있는 모든 작업을 수행할 수 있습니다.또, idx 를 테이블 정의내에서 정의해 액세스 할 수도 있습니다.
BEGIN
SET @curren_val = (SELECT PractitionerId FROM #Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @curren_val
SET @i = @i + 1
END
제가 만든 절차는FOREACH
와 함께CURSOR
모든 테이블에서 사용할 수 있습니다.
사용 예:
CREATE TABLE #A (I INT, J INT)
INSERT INTO #A VALUES (1, 2), (2, 3)
EXEC PRC_FOREACH
#A --Table we want to do the FOREACH
, 'SELECT @I, @J' --The execute command, each column becomes a variable in the same type, so DON'T USE SPACES IN NAMES
--The third variable is the database, it's optional because a table in TEMPB or the DB of the proc will be discovered in code
결과는 각 행에 대해 2가 선택됩니다.의 구문UPDATE
를 부수고FOREACH
힌트에 써있네요.
프로시저 코드는 다음과 같습니다.
CREATE PROC [dbo].[PRC_FOREACH] (@TBL VARCHAR(100) = NULL, @EXECUTE NVARCHAR(MAX)=NULL, @DB VARCHAR(100) = NULL) AS BEGIN
--LOOP BETWEEN EACH TABLE LINE
IF @TBL + @EXECUTE IS NULL BEGIN
PRINT '@TBL: A TABLE TO MAKE OUT EACH LINE'
PRINT '@EXECUTE: COMMAND TO BE PERFORMED ON EACH FOREACH TRANSACTION'
PRINT '@DB: BANK WHERE THIS TABLE IS (IF NOT INFORMED IT WILL BE DB_NAME () OR TEMPDB)' + CHAR(13)
PRINT 'ROW COLUMNS WILL VARIABLE WITH THE SAME NAME (COL_A = @COL_A)'
PRINT 'THEREFORE THE COLUMNS CANT CONTAIN SPACES!' + CHAR(13)
PRINT 'SYNTAX UPDATE:
UPDATE TABLE
SET COL = NEW_VALUE
WHERE CURRENT OF MY_CURSOR
CLOSE CURSOR (BEFORE ALL LINES):
IF 1 = 1 GOTO FIM_CURSOR'
RETURN
END
SET @DB = ISNULL(@DB, CASE WHEN LEFT(@TBL, 1) = '#' THEN 'TEMPDB' ELSE DB_NAME() END)
--Identifies the columns for the variables (DECLARE and INTO (Next cursor line))
DECLARE @Q NVARCHAR(MAX)
SET @Q = '
WITH X AS (
SELECT
A = '', @'' + NAME
, B = '' '' + type_name(system_type_id)
, C = CASE
WHEN type_name(system_type_id) IN (''VARCHAR'', ''CHAR'', ''NCHAR'', ''NVARCHAR'') THEN ''('' + REPLACE(CONVERT(VARCHAR(10), max_length), ''-1'', ''MAX'') + '')''
WHEN type_name(system_type_id) IN (''DECIMAL'', ''NUMERIC'') THEN ''('' + CONVERT(VARCHAR(10), precision) + '', '' + CONVERT(VARCHAR(10), scale) + '')''
ELSE ''''
END
FROM [' + @DB + '].SYS.COLUMNS C WITH(NOLOCK)
WHERE OBJECT_ID = OBJECT_ID(''[' + @DB + '].DBO.[' + @TBL + ']'')
)
SELECT
@DECLARE = STUFF((SELECT A + B + C FROM X FOR XML PATH('''')), 1, 1, '''')
, @INTO = ''--Read the next line
FETCH NEXT FROM MY_CURSOR INTO '' + STUFF((SELECT A + '''' FROM X FOR XML PATH('''')), 1, 1, '''')'
DECLARE @DECLARE NVARCHAR(MAX), @INTO NVARCHAR(MAX)
EXEC SP_EXECUTESQL @Q, N'@DECLARE NVARCHAR(MAX) OUTPUT, @INTO NVARCHAR(MAX) OUTPUT', @DECLARE OUTPUT, @INTO OUTPUT
--PREPARE TO QUERY
SELECT
@Q = '
DECLARE ' + @DECLARE + '
-- Cursor to scroll through object names
DECLARE MY_CURSOR CURSOR FOR
SELECT *
FROM [' + @DB + '].DBO.[' + @TBL + ']
-- Opening Cursor for Reading
OPEN MY_CURSOR
' + @INTO + '
-- Traversing Cursor Lines (While There)
WHILE @@FETCH_STATUS = 0
BEGIN
' + @EXECUTE + '
-- Reading the next line
' + @INTO + '
END
FIM_CURSOR:
-- Closing Cursor for Reading
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR'
EXEC SP_EXECUTESQL @Q --MAGIA
END
커서는 보통 끔찍한 악으로 간주되지만 FAST_FORWARD 커서의 경우라고 생각합니다.이것은 TSQL에서 FORACH에 가장 가까운 것입니다.
저는 이것을 하는 매우 효과적이고 읽기 쉬운 방법을 생각해 냈습니다.
임시 테이블을 만들고 반복할 레코드를 여기에 넣습니다.
사용하다
WHILE @@ROWCOUNT <> 0
반복하다한 번에 한 줄씩 하려면
SELECT TOP 1 <fieldnames>
b. 해당 행의 고유 ID를 변수에 저장합니다.
작업을 수행한 후 스텝 3b에서 저장한 ID에 따라 임시 테이블에서 행을 삭제합니다.
여기 암호가 있습니다.죄송합니다. 질문의 변수 이름 대신 제 변수 이름을 사용하고 있습니다.
DECLARE @tempPFRunStops TABLE (
ProformaRunStopsID int,
ProformaRunMasterID int,
CompanyLocationID int,
StopSequence int
);
INSERT @tempPFRunStops (ProformaRunStopsID, ProformaRunMasterID, CompanyLocationID, StopSequence)
SELECT
ProformaRunStopsID,
ProformaRunMasterID,
CompanyLocationID,
StopSequence
FROM ProformaRunStops
WHERE ProformaRunMasterID IN (
SELECT ProformaRunMasterID
FROM ProformaRunMaster
WHERE ProformaId = 15 )
-- SELECT * FROM @tempPFRunStops
WHILE @@ROWCOUNT <> 0 -- << I dont know how this works
BEGIN
SELECT TOP 1 * FROM @tempPFRunStops
-- I could have put the unique ID into a variable here
SELECT 'Ha' -- Do Stuff
DELETE @tempPFRunStops
WHERE ProformaRunStopsID = (SELECT TOP 1 ProformaRunStopsID FROM @tempPFRunStops)
END
언급URL : https://stackoverflow.com/questions/18513986/how-to-write-a-foreach-in-sql-server
'source' 카테고리의 다른 글
sql 문에서 대괄호 []를 사용하는 이유는 무엇입니까? (0) | 2023.04.07 |
---|---|
SQL Server의 select 문에 TOP가 있는 변수를 동적으로 만들지 않고 사용 (0) | 2023.04.07 |
엔티티 프레임워크 마이그레이션의 테이블 및 열 이름 변경 (0) | 2023.04.07 |
Springboot: org.hibernate.Mapping Exception:org.hibernate의 생성자를 가져올 수 없습니다.persister.parsister.parster.parsterSingleTableEntityPersister (0) | 2023.04.02 |
WooCommerce - 커스텀 주문 상태 변경 시 커스텀 이메일 보내기 (0) | 2023.04.02 |