Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 仅合并源中的非空字段,保留目标中的其他字段不变_Sql_Sql Server_Tsql - Fatal编程技术网

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

Sql 仅合并源中的非空字段,保留目标中的其他字段不变,sql,sql-server,tsql,Sql,Sql Server,Tsql,真实数据有更多的列。示例目标表具有唯一的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

真实数据有更多的列。示例目标表具有唯一的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”,则将目标字段设置为空

我不会添加任何记录,只会匹配目标中的现有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
听起来你需要:

SET Target.Field = NULLIF(ISNULL(Source.Field,Target.Field),'99999')
听起来你需要:

SET Target.Field = NULLIF(ISNULL(Source.Field,Target.Field),'99999')
我在想:

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}'

,我想:

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}

我认为您没有处理这个要求:“如果源代码是“99999”,那么将目标字段设置为null。”我不需要清除整个记录,只需要清除特定字段。@TabAlleman。我最初误解了这个要求(因为它适用于整个记录),但我添加了它的逻辑。我认为您没有处理这个要求:“如果源是“99999”,那么将目标字段设置为NULL。”我不需要清除整个记录,只需要清除特定字段。@TabAlleman。我最初误解了这个要求(因为它适用于整个记录),但我为它添加了逻辑。@shorton,如果给定源值,则内部
ISNULL
将选择源值,如果源值为null,则选择目标值。因此,如果用户通过
99999
,将选择该值。如果两个参数彼此相等,则外部
NULLIF
将返回
NULL
。因此,当
ISNULL
返回
99999
时,
NULLIF
将返回
NULL
。这是一个相当优雅的解决方案+1.@shorton,如果给定源值,则内部
ISNULL
将选择源值,如果源值为null,则选择目标值。因此,如果用户通过
99999
,将选择该值。如果两个参数彼此相等,则外部
NULLIF
将返回
NULL
。因此,当
ISNULL
返回
99999
时,
NULLIF
将返回
NULL
。这是一个相当优雅的解决方案+谢谢各位。合并对第一部分有效,Tab的建议对第二部分有效。我看不出有什么办法能把你们俩的帮助都归功于我。非常感谢你们,谢谢你们。合并对第一部分有效,Tab的建议对第二部分有效。我看不出有什么办法能把你们俩的帮助都归功于我。非常感谢你们两位。