DECLARE语句中的子查询返回多个值

时间:2012-12-19 17:57:01

标签: sql-server stored-procedures declare

我有下面的存储过程,我需要帮助。其目的是找到暂存数据库和生产数据库之间的差异。当找到差异时,存储过程将使用正确的信息更新生产数据库。问题是有时DB之间存在多个差异。存储过程一次只能处理DB之间的一个差异。我希望存储过程能够处理尽可能多的差异。如果它一次只能处理一个差异,则存储过程需要不断运行。非常感谢任何想法或帮助。

            `BEGIN TRANSACTION

            DECLARE @FILENUM NVARCHAR(30)

            SET @FILENUM = ( SELECT TOP 1 B.ID FROM DBO.ABC_FILE_NUMBER F WITH ( NOLOCK )

                            JOIN DBO.REL_PRIMARY_NUMBER R WITH ( NOLOCK ) ON F.ID = R.FILE_NUMBER_ID

                            JOIN DBO.ABC_PRIMARY_NUMBER P WITH ( NOLOCK ) ON R.PRIMARY_NUMBER_ID = P.ID

                            JOIN DBO.STAGINGDATA S WITH ( NOLOCK ) ON F.FILE_NUMBER_ALIAS = S.ID

                            WHERE S.PRIMARYNUMBER <> P.PRIMARY_NUMBER_ALIAS)

            DECLARE @PRIMNUM NVARCHAR(30)

            SET @PRIMNUM = ( SELECT DISTINCT P.ID FROM DBO.STAGINGDATA S WITH ( NOLOCK )

                            JOIN DBO.ABC_PRIMARY_NUMBER P WITH ( NOLOCK ) ON P.PRIMARY_NUMBER_ALIAS = S.PRIMARYNUMBER

                            WHERE S.ID = ( SELECT F.FILE_NUMBER_ALIAS FROM ABC_FILE_NUMBER WHERE ID = @FILENUM))

            UPDATE  DBO.REL_PRIMARY_NUMBER
            SET     PRIMARY_NUMBER_ID = @PRIMNUM
            WHERE   FILE_NUMBER_ID = @FILENUM

            UPDATE  DBO.ABC_WORKSPACE
            SET     PRIMARY_NUMBER_ID = @PRIMNUM
            WHERE   FILE_NUMBER_ID = @FILENUM

            UPDATE  DBO.ABC_DOCUMENT
            SET     PRIMARY_NUMBER_ID = @PRIMNUM
            WHERE   FILE_NUMBER_ID  = @FILENUM

            UPDATE  DBO.ABC_FILE_NUMBER
            SET     MODIFIED_TIME = GETDATE(), MODIFIED_BY_ID = '21403'
            WHERE   FILE_NUMBER_ID = @FILENUM

            COMMIT`

1 个答案:

答案 0 :(得分:0)

您可以构建一个循环,如下所示“遍历”每个@FILENUM,并使用您现在使用的相同脚本完成工作。更好的选择是重写每个DML操作以基于集合的方式执行工作并立即对所有行执行操作,但这可能不适合您,具体取决于您正在执行的其他操作。

这是一个循环遍历每个FileNum的简单设置:

declare @Process table (ProcessId int identity(1,1), FileNum nvarchar(30));

-- stage *all* the fileNums (perhaps in some order?)
insert into @Process (FileNum)
    SELECT B.ID FROM DBO.ABC_FILE_NUMBER F WITH ( NOLOCK )
    JOIN DBO.REL_PRIMARY_NUMBER R WITH ( NOLOCK ) ON F.ID = R.FILE_NUMBER_I
    JOIN DBO.ABC_PRIMARY_NUMBER P WITH ( NOLOCK ) ON R.PRIMARY_NUMBER_ID = P.ID
    JOIN DBO.STAGINGDATA S WITH ( NOLOCK ) ON F.FILE_NUMBER_ALIAS = S.ID
    WHERE S.PRIMARYNUMBER <> P.PRIMARY_NUMBER_ALIAS


declare @ProcessId int,
        @FileNum nvarchar(30);

select @ProcessId = min(ProcessId) from @Process;

while @ProcessId is not null
begin

    select @FileNum = FileNum from @Process where ProcessId = @ProcessId;

    print 'Working on FileNum: ' + @FileNum;
    /*
        do your work here
    */

    select @ProcessId = min(ProcessId) from @Process where ProcessId > @ProcessId;

end

基于集合的操作看起来像:

declare @Stage table (FileNum nvarchar(30), PrimNum nvarchar(30) primary key  (FileNum));

-- stage the (FileNum:PrimNum) dataset
insert into @Stage (FileNum)
    select FileNum, PrimNum from dbo.yourTables where yourColumn ...

--now perform set based updates
UPDATE  rpn
SET     PRIMARY_NUMBER_ID = s.PRIMNUM
from    @Stage s 
join    DBO.REL_PRIMARY_NUMBER rpn on
        s.FileNum = rpn.FILE_NUMBER_ID

UPDATE  aw
SET     PRIMARY_NUMBER_ID = s.PRIMNUM
from    @Stage s
join    DBO.ABC_WORKSPACE aw on
        s.FileNum = aw.FILE_NUMBER_ID

-- and so on...