【问题标题】:Subquery in DECLARE statement brings back more than one valueDECLARE 语句中的子查询带回多个值
【发布时间】:2012-12-19 17:57:01
【问题描述】:

我有下面需要帮助的存储过程。其目的是找出暂存数据库和生产数据库之间的差异。当它发现差异时,存储过程将使用正确的信息更新生产数据库。问题是有时数据库之间存在不止一个差异。存储过程一次只能处理 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`

【问题讨论】:

    标签: sql-server stored-procedures declare


    【解决方案1】:

    您可以构建如下循环来“遍历”每个@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...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      相关资源
      最近更新 更多