仅合并源中的非空字段,目标中的其他字段保持不变

时间:2019-04-04 14:45:46

标签: sql sql-server tsql

实际数据具有更多列。 Sample Target表具有唯一的ID字段。数据字段具有现有数据。需要更新记录,但仅某些字段会更新。

-- Original/target table
DECLARE @target TABLE (
    ID      varchar(4) NOT NULL,
    x        int NULL,
    y        int NULL,
    z        int NULL );

INSERT INTO @target (ID, x, y, z)
VALUES ('A1', NULL, 2, 3),
       ('A2', 1, 2, NULL),
       ('C4', 1, 2, 3),
       ('Z5', 1, 2, 3)
       ;

--- Updates needed:
DECLARE @updates TABLE (
    ID      varchar(4) NOT NULL,
    x        int NULL,
    y        int NULL,
    z        int NULL );

INSERT INTO @updates (ID, x, y, z)
VALUES ('A1', NULL , 101, NULL),
       ('A2', 201, NULL, NULL),
       ('C4', NULL, NULL, 40),
       ('Z5', NULL, NULL, 99999)

我需要用户向我发送数据更新,我将使用这些数据更新/合并到目标表。用户可以更新特定字段,但不能更新其他字段。因此,当源表具有值时,我需要它来更新相应的目标字段,但保持其他字段(源中为空)不变。仅在源中明确列出目标字段(不为null)时更改它。

例如,ID = A1的源记录的“ y”的更新值为101。合并后,我需要A1的目标记录包含:NULL,101、3

我还需要一种方法来“清除”目标中的记录。我认为也许可以对记录ID Z5中显示的数据使用特殊值,例如“ 99999”。如果源是“ 99999”,则将目标字段设置为NULL。

我将不添加任何记录,仅匹配目标中的现有ID。

更新:

此解决方案结合了两个答案,似乎很有效:

update t
    set x = coalesce(u.x, t.x),
        y = coalesce(u.y, t.y),
        z = coalesce(u.z, t.z)
from @target t join
     @updates u
     on t.id = u.id;

update t
    set 
    x = NULLIF(ISNULL(u.x,t.x),'99999'),
    y = NULLIF(ISNULL(u.y,t.y),'99999'),
    z = NULLIF(ISNULL(u.z,t.z),'99999')
from @target t join
     @updates u
     on t.id = u.id;

select * from @target

2 个答案:

答案 0 :(得分:2)

您需要的声音

SET Target.Field = NULLIF(ISNULL(Source.Field,Target.Field),'99999')

答案 1 :(得分:0)

我在想:

update t
    set x = coalesce(u.x, t.x),
        y = coalesce(u.y, t.y),
        z = coalesce(u.z, t.z)
from @target t join
     @updates u
     on t.id = u.id;

如果您想清除整个记录,我建议向@updates添加一个附加标志:

update t
    set x = (case when u.clear_record = 1 then null
                  when u.x is not null then u.x
                  else t.x
             end),
        y = (case when u.clear_record = 1 then null
                  when u.y is not null then u.y
                  else t.y
             end),
        z = (case when z.clear_record = 1 then null
                  when u.z is not null then u.z
                  else t.z
             end)
from @target t join
     @updates u
     on t.id = u.id;

编辑:

您可以通过使用类似逻辑的特殊值来清除特定字段:

update t
    set x = (case when u.clear_record = 1 or u.x = '99999' then null
                  when u.x is not null then u.x
                  else t.x
             end),
        y = (case when u.clear_record = 1 or u.y = '9999'9 then null
                  when u.y is not null then u.y
                  else t.y
             end),
        z = (case when z.clear_record = 1 or u.z = '99999' then null
                  when u.z is not null then u.z
                  else t.z
             end)
from @target t join
     @updates u
     on t.id = u.id;

但是,我不会使用'99999'这样的特殊值。如果值是字符串,则建议使用空字符串('')或'<null>''{null}'