表连接与覆盖

时间:2014-02-14 13:10:59

标签: sql sql-server sql-server-2008

我有2个表 - 实际和建议 - 如下:

ACTUAL
    Id|desc|Allocation|changeBit
    1|X|20||
    2|y|30||

PROPOSED
        Id|desc|Allocation|changeBit
        1|X|30|U|
        3|z|40|I|

所寻求的结果如下:

    1|X|30|U|
    2|y|30||
    3|z|40|I|

'U'位导致'proposed'中的记录覆盖'actual'。 提议中的'I'位表示需要添加'新'记录。

实现这一目标最优雅的方法是什么?

理想情况下,我希望避免创建临时表,然后插入更新 我正在使用sql-server 2008。

3 个答案:

答案 0 :(得分:1)

您应该使用full outer join加入两个表,然后仅在建议值不存在时使用coalesce获取实际值:

SELECT          COALESCE (p.id, a.id) AS id, 
                COALESCE (p.desc, a.desc) AS desc,
                COALESCE (p.allocation, a.allocation) AS allocation,
                COALESCE (p.changebit, a.changebit) AS changebit
FROM            actual a
FULL OUTER JOIN proposed p ON a.id = p.id

答案 1 :(得分:1)

我倾向于使用union allnot exists来解决这个问题。我发现coalesce()方法中的列上的isnull()full outer join不够优雅。

select Id, desc, Allocation, changeBit
from proposed
union all
select Id, desc, Allocation, changeBit
from actual a
where not exists (select 1 from proposed p where a.id = p.id);

编辑:

如果您想进行验证,则基本上是:

select Id, desc, Allocation, changeBit
from proposed
where changebit in ('U', 'I')
union all
select Id, desc, Allocation, changeBit
from actual a
where not exists (select 1 from proposed p where a.id = p.id);

真正测试有效的“U”与“I”是更加密集的,似乎是不必要的(并不是原始问题的真正部分)。您可能应该提出另一个问题,并准确解释当非实际记录更新时要执行的操作,或者不存在的记录插入。

答案 2 :(得分:0)

这有点偏离基础,但根据您的上一条语句判断,您似乎正在使用此查询生成INSERTUPDATE语句。由于您使用的是SQL-Server 2008,您是否考虑过使用MERGE语句在一个命令中执行此操作,而不是三个(查询,插入,更新)?

假设PROPOSED包含您的更改,您可以执行以下操作:

MERGE ACTUAL AS A
USING PROPOSED AS P
    ON A.Id = P.Id
WHEN MATCHED
    THEN UPDATE
    SET A.Allocation = P.Allocation
WHEN NOT MATCHED
    THEN INSERT (Id, [Desc], Allocation)
    VALUES (Id, [Desc], Allocation);

使用此功能,您可以删除changeBit列,因为MERGE语句会为您提供INSERTUPDATE

SQLFiddle