특정 방식으로 사용자 데이터를 변경하는 저장 프로 시저가 있습니다. user_id를 전달하면됩니다. 테이블에서 쿼리를 실행하고 각 user_id마다 해당 user_id에서 저장 프로 시저를 한 번 실행합니다.
이것에 대한 쿼리를 어떻게 작성합니까?
특정 방식으로 사용자 데이터를 변경하는 저장 프로 시저가 있습니다. user_id를 전달하면됩니다. 테이블에서 쿼리를 실행하고 각 user_id마다 해당 user_id에서 저장 프로 시저를 한 번 실행합니다.
이것에 대한 쿼리를 어떻게 작성합니까?
답변:
커서를 사용하십시오
부록 : [MS SQL 커서 예]
declare @field1 int
declare @field2 int
declare cur CURSOR LOCAL for
select field1, field2 from sometable where someotherfield is null
open cur
fetch next from cur into @field1, @field2
while @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
exec uspYourSproc @field1, @field2
fetch next from cur into @field1, @field2
END
close cur
deallocate cur
MS SQL에서는 다음 기사가 있습니다.
커서는 설정 기반 작업보다 느리지 만 수동 while 루프보다 빠릅니다. 이 SO 질문에 대한 자세한 내용
부록 2 : 몇 개 이상의 레코드를 처리 할 경우 먼저 임시 테이블로 가져 와서 임시 테이블 위로 커서를 이동하십시오. 이렇게하면 SQL이 테이블 잠금으로 에스컬레이션되지 않고 작업 속도가 빨라집니다.
부록 3 : 물론 각 사용자 ID에 대해 스토어드 프로 시저가 수행하는 작업을 인라인하고 전체를 단일 SQL 업데이트 명령문으로 실행할 수 있다면 최적입니다.
루프가 필요한 경우 메소드를 변경하십시오!
상위 스토어드 프로 시저에서 처리해야하는 데이터가 포함 된 #temp 테이블을 작성하십시오. 자식 저장 프로 시저를 호출하면 #temp 테이블이 표시되고 커서 또는 루프없이 전체 데이터 세트를 사용하여 처리 할 수 있습니다.
이것은 실제로이 하위 저장 프로 시저가 수행하는 작업에 따라 다릅니다. UPDATE-ing하는 경우 #temp 테이블에서 "update from"조인을 수행하고 루프없이 하나의 명령문으로 모든 작업을 수행 할 수 있습니다. INSERT 및 DELETE에 대해서도 동일하게 수행 할 수 있습니다. IF로 여러 번 업데이트해야하는 경우 UPDATE FROM
#temp 테이블을 사용 하여 여러 번 업데이트하고 CASE 문 또는 WHERE 조건을 사용할 수 있습니다.
데이터베이스에서 작업 할 때 루핑의 사고 방식을 잃어 버리려고하면 실제 성능이 저하되고 잠금 / 차단이 발생하고 처리 속도가 느려집니다. 어디에서나 반복하면 시스템이 제대로 확장되지 않으며 사용자가 느린 새로 고침에 대해 불평하기 시작할 때 속도를 높이기가 매우 어렵습니다.
이 절차의 내용을 루프에 호출하려면 10 번 중 9 번을 베팅하고 일련의 행에서 작동하도록 작성할 수 있습니다.
이 대체와 같은 것이 테이블 및 필드 이름에 필요합니다.
Declare @TableUsers Table (User_ID, MyRowCount Int Identity(1,1)
Declare @i Int, @MaxI Int, @UserID nVarchar(50)
Insert into @TableUser
Select User_ID
From Users
Where (My Criteria)
Select @MaxI = @@RowCount, @i = 1
While @i <= @MaxI
Begin
Select @UserID = UserID from @TableUsers Where MyRowCount = @i
Exec prMyStoredProc @UserID
Select
@i = @i + 1, @UserID = null
End
저장 프로 시저가 수행하는 작업을 복제하기 위해 사용자 정의 함수를 사용하여이를 수행 할 수 없습니까?
SELECT udfMyFunction(user_id), someOtherField, etc FROM MyTable WHERE WhateverCondition
여기서 udfMyFunction은 사용자 ID를 가져 와서 필요한 모든 기능을 수행하는 함수입니다.
http://www.sqlteam.com/article/user-defined-functions를 참조하십시오 .조금 더 많은 배경을 를
가능한 경우 커서를 피해야한다는 데 동의합니다. 그리고 보통 가능합니다!
(물론, 내 대답은 SP에서 출력을 얻는 데 관심이 있고 실제 데이터를 변경하지 않을 것을 전제로합니다. 원래 질문과는 달리 "특정 방식으로 사용자 데이터 변경"을 발견했습니다. 가능한 해결책으로 이것을 제공하겠다고 생각했습니다. 당신의 행동에 달려 있습니다.)
테이블 변수 또는 임시 테이블을 사용하십시오.
앞에서 언급했듯이 커서는 최후의 수단입니다. 주로 많은 리소스를 사용하기 때문에 잠금 문제가 발생하며 SQL을 올바르게 사용하는 방법을 이해하지 못하고 있다는 신호일 수 있습니다.
참고 사항 : 커서를 사용하여 테이블의 행을 업데이트하는 솔루션을 발견했습니다. 약간의 조사 끝에 모든 것이 단일 UPDATE 명령으로 대체 될 수 있음이 밝혀졌습니다. 그러나이 경우 저장 프로 시저를 실행해야 할 경우 단일 SQL 명령이 작동하지 않습니다.
다음과 같이 테이블 변수를 작성하십시오 (많은 데이터로 작업 중이거나 메모리가 부족한 경우 임시 테이블을 대신 사용하십시오).
DECLARE @menus AS TABLE (
id INT IDENTITY(1,1),
parent NVARCHAR(128),
child NVARCHAR(128));
그만큼 id
중요하다.
교체 parent
하고child
좋은 데이터, 예를 들어 관련 식별자 또는 데이터의 전체 집합에 작동합니다.
테이블에 데이터를 삽입하십시오. 예 :
INSERT INTO @menus (parent, child)
VALUES ('Some name', 'Child name');
...
INSERT INTO @menus (parent,child)
VALUES ('Some other name', 'Some other child name');
일부 변수를 선언하십시오.
DECLARE @id INT = 1;
DECLARE @parentName NVARCHAR(128);
DECLARE @childName NVARCHAR(128);
마지막으로 테이블의 데이터에 while 루프를 만듭니다.
WHILE @id IS NOT NULL
BEGIN
SELECT @parentName = parent,
@childName = child
FROM @menus WHERE id = @id;
EXEC myProcedure @parent=@parentName, @child=@childName;
SELECT @id = MIN(id) FROM @menus WHERE id > @id;
END
첫 번째 선택은 임시 테이블에서 데이터를 가져옵니다. 두 번째 선택은 @id를 업데이트합니다.MIN
선택된 행이 없으면 null을 반환합니다.
다른 방법은 테이블에 행이있는 동안 루프 SELECT TOP 1
하고 임시 테이블에서 선택한 행을 제거하는 것입니다.
WHILE EXISTS(SELECT 1 FROM @menuIDs)
BEGIN
SELECT TOP 1 @menuID = menuID FROM @menuIDs;
EXEC myProcedure @menuID=@menuID;
DELETE FROM @menuIDs WHERE menuID = @menuID;
END;
Dave Rincon의 동적 쿼리 방식은 커서를 사용하지 않으며 작고 쉽습니다. 공유해 주셔서 감사합니다.
그러나 Azure SQL에 대한 요구와 쿼리에 "고유성"이 필요한 경우 다음과 같이 코드를 수정해야했습니다.
Declare @SQL nvarchar(max);
-- Set SQL Variable
-- Prepare exec command for each distinctive tenantid found in Machines
SELECT @SQL = (Select distinct 'exec dbo.sp_S2_Laser_to_cache ' +
convert(varchar(8),tenantid) + ';'
from Dim_Machine
where iscurrent = 1
FOR XML PATH(''))
--for debugging print the sql
print @SQL;
--execute the generated sql script
exec sp_executesql @SQL;
나는 이것이 누군가를 돕기를 바랍니다 ...