2014-03-25 60 views
0

我想编写一个更新语句,通过加入MASTER_ID来比较新的代码表和旧的代码。然后如果NEW_CODE.CODE = 1234 AND OLD_CODE.CODE_ID不在CODE_MAPPING表中,则SET NEW_CODE.CODE_ID = OLD_CODE.CODE_ID AND NEW_CODE.SEQ_NO = OLD_CODE.SEQ_NO。这是我迄今为止的内容,但是如果在CODE_ID列中获得空值,它似乎无法正确更新。我想我需要做一个自我加入,但是我没有做任何事情似乎能够奏效,不胜感激。如何将此Access内部连接查询转换为SQL Server?

我有三个表数据如下:

**NEW_CODE** 

    MASTER_ID  SEQ_NO  CODE_ID  CODE 
    100   0   XX   1234 
    200   0      5555 
    300   0   XX   1234 
    300   0   XX   1234 

**OLD_CODE** 

    MASTER_ID SEQ_NO CODE_ID 
    100   1  D1   
    200   1  A1 
    300   1   
    300   2  Z1 

**CODE_MAPPING** 

    CODE_ID 
    A1 
    B1 
    C1 
    D1 

UPDATE语句:

UPDATE NEW 
    SET SEQ_NO = OLD.SEQ_NO, 
    CODE_ID = OLD.CODE_ID 

    FROM NEW_CODE  NEW 
    INNER JOIN OLD_CODE  OLD 
    ON NEW.MASTER_ID = OLD.MASTER_ID 

LEFT JOIN CODE_MAPPING  CM 
    ON OLD.CODE_ID = CM.CODE_ID 
    WHERE NEW.CODE = 1234 
    AND CM.CODE_ID IS NULL 

更新后的表应该是这样的:

**UPDATED NEW_CODE** 

     MASTER_ID  SEQ_NO  CODE_ID  CODE 
     100   0   XX   1234 
     200   0      5555 
     300   1      1234 
     300   2   Z1   1234 

所以,唯一的应该更新的是具有MASTER_ID o的两行f 300.但由于某些原因,我得到的结果如下:

**CURRENT RESULT NEW_CODE** 

     MASTER_ID  SEQ_NO  CODE_ID  CODE 
     100   0   XX   1234 
     200   0      5555 
     300   2   Z1   1234 
     300   2   Z1   1234 

回答

1

当你有两行用相同的标识符(MASTER_ID),需要TSQL而不是一个简单的声明。

要更新的行的先决条件: NEW中的每一行都可以与OLD中的一行匹配并反向。 我们需要一个标准来确定NEW中更新的行。我在这里使用SEQ_NO = 0。

  1. 需要OLD和NEW中每一行的唯一键。您的示例数据不包含唯一的密钥。所以我加一个旧的和一个新的。它可以在最后被丢弃。

    ALTER TABLE OLD添加IDX INT IDENTITY(1,1) ALTER TABLE NEW添加IDX INT IDENTITY(1,1)

  2. 声明上OLD一个光标(只要更新的行)

    DECLARE @IdxOld INT DECLARE @IdxNew诠释

    DECLARE MY_CURSOR CURSOR 本地静态READ_ONLY FORWARD_ONLY FOR SELECT IDX 旧 WHERE NOT EXISTS(SELECT * FROM CODE_MAPPING CM WHERE OLD.CODE_ID = CM。CODE_ID)

  3. 做旧的foreach和更新。新

    OPEN MY_CURSOR FETCH NEXT FROM MY_CURSOR INTO @IdxId WHILE @@ FETCH_STATUS = 0 BEGIN

    SELECT @IdxNew = Min(Idx) -- min to get only one row 
        FROM NEW 
        INNER JOIN OLD_CODE OLD ON NEW.MASTER_ID = OLD.MASTER_ID 
    WHERE NEW.CODE = 1234 
        AND OLD.IDX = @IdxOld -- current row from old 
        AND SEQ_NO=0 -- row not updated yet   
    
    UPDATE NEW 
        SET SEQ_NO = OLD.SEQ_NO, 
        CODE_ID = OLD.CODE_ID 
    FROM NEW_CODE NEW 
        INNER JOIN OLD_CODE OLD ON NEW.MASTER_ID = OLD.MASTER_ID 
    WHERE NEW.IDX = @IdxNew 
        AND OLD.IDX = @IdxOld 
    
    FETCH NEXT FROM MY_CURSOR INTO @IdxId 
    

    END CLOSE MY_CURSOR DEALLOCATE MY_CURSOR

  4. 删除IDX列

    ALTER TABLE OLD drop列IDX

    ALTER TABLE新drop列IDX

+0

这仍然会得到相同的结果,它只是更新Z1两次,因为我需要它将CODE_ID更新为Z1的第一行,然后查看第二行的MASTER_ID为300,CODE_ID为空,并且不在CODE_MAPPING表中。所以在预期的结果中,行的CODE_ID应该是Z1并且是空的。 – swingard

+0

编辑我的答案,因为我需要格式化和很多字符。 –

+0

谢谢光标正是我一直在寻找的! – swingard

0

别名在更新中不匹配。 。 。即new不是new_code。试试这个:

UPDATE NC 
    SET SEQ_NO = OC.SEQ_NO, 
     CODE_ID = OC.CODE_ID 
    FROM NEW_CODE NC INNER JOIN 
     OLD_CODE OC 
     ON NC.MASTER_ID = OC.MASTER_ID LEFT JOIN 
     CODE_MAPPING CM 
     ON OC.CODE_ID = CM.CODE_ID 
    WHERE NC.CODE = 1234 AND CM.CODE_ID IS NULL; 
+0

我曾在我刚刚更新了良好的抓别名一个错误,但它是我已经发布了完全相同的代码。我遇到了一个处理MASTER_ID的问题,它有多于一行。现在它只是取出第一个不在CODE_MAPPING表中的非NULL CODE_ID,并更新所有具有1234的CODE值的行。我需要循环并更新每个不在CODE_MAPPING表中的CODE_ID。我不知道是否需要另一个INNER JOIN或某种CASE语句.... – swingard

相关问题