简体   繁体   English

SQL Server-如果新插入行; 更新(如果存在)

[英]SQL Server - Insert row if new; Update if exists

Given: 鉴于:

Master Table: 主表:

A  B  C
a1 b1 NULL
a3 b2 NULL

New_Row Table: 新行表:

A  B  C
a1 b1 c1
a2 b2 c2

Desired Output: 所需输出:

A  B  C 
a1 b1 c1
a2 b2 c2
a3 b2 NULL

I need a query that compares each columns between the Master Table and New_Row Table, and either updates the Master Table rows if all other columns in that row is identical or inserts a new row if the other columns in that row are different. 我需要一个查询来比较主表和New_Row表之间的每一列,如果该行中的所有其他列相同,则更新主表行,或者如果该行中的其他列不同,则插入新行。

In the above example, the first row from the New_Row Table matches with the first row in the Master Table with the exception of the NULL value (assume Master Table is missing this data) so c1 is populated in the desired output. 在上面的示例中,New_Row表中的第一行与主表中的第一行匹配,但NULL值除外(假定主表缺少此数据),因此在所需的输出中填充了c1。 The second row from the New_Row Table doesn't match with any of the rows in the Master Table (as there is no a3 b2 rows in the Master), so it gets inserted in the desired output as a new row. New_Row表中的第二行与主表中的任何行都不匹配(因为主表中没有a3 b2行),因此它将作为新行插入到所需的输出中。

How would I write this query? 我将如何编写此查询?

SQL Server supports the MERGE statement to perform INSERT , UPDATE or DELETE actions in a single query. SQL Server支持MERGE语句以在单个查询中执行INSERTUPDATEDELETE操作。

You can find details on this statement here: https://docs.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql 您可以在此处找到有关此语句的详细信息: https : //docs.microsoft.com/zh-cn/sql/t-sql/statements/merge-transact-sql

MERGE [master_table] AS TARGET
USING [new_row_table] AS SOURCE
ON (TARGET.A = SOURCE.A) AND (TARGET.B = SOURCE.B)
WHEN MATCHED THEN
    UPDATE SET TARGET.C = SOURCE.C
WHEN NOT MATCHED BY TARGET THEN
    INSERT (A, B, C)
    VALUES (SOURCE.A, SOURCE.B, SOURCE.C);

One caveat - MERGE is only supported in SQL Server 2008 and above. 一个警告MERGE仅在SQL Server 2008及更高版本中受支持。

So without a unique key on either of your tables, this is a little dicier, but still doable. 因此,在两个表中都没有唯一键的情况下,这有点麻烦,但仍然可行。 You can do this either with a MERGE statement, or an explicit transaction. 您可以使用MERGE语句或显式事务来执行此操作。 Which one you use is largely up to you. 您使用哪一个主要取决于您。 Personally I'm not a huge fan of MERGE because I find the syntax clunky and it can have some weird behaviors, but that's up to you. 我个人不是MERGE忠实MERGE因为我发现语法很笨拙,并且可能会有一些奇怪的行为,但这取决于您。 Also, i'm not sure what if any unique constraints exist on the table(s) but if there are none, and duplicates are possible, you may want to avoid MERGE as it doesn't play nicely with updating non-unique data sets. 另外,我不知道如果有什么在桌子上(一个或多个)存在惟一性约束,但如果没有,并且复制是可能的,你可能希望避免MERGE ,因为它不与更新非唯一的数据集发挥很好。

With either approach, you also need to be careful how you're handling NULL values. 无论采用哪种方法,您都需要注意如何处理NULL值。 If you just do a straight comparison (eg tc = sc ) and one of the columns is null, that will never evaulate as true (since a null never equals anything; even another null ). 如果您只是进行直接比较(例如tc = sc ),并且其中一列为null,则该值将永远不会作为true进行评估(因为null永远不等于任何东西;甚至另一个null )。 If that's something you care about, you'd need to either replace the nulls with a placeholder value (say, isnull(tc, '') = isnull(sc, '') or ad an additional check for whether the column(s) are null (eg (tc is null or sc is null or tc = sc) Setup Data 如果您对此很在意,则需要用占位符值替换空值(例如, isnull(tc, '') = isnull(sc, '')或者另外检查该列是否为空(例如(tc is null or sc is null or tc = sc) 设置数据

if object_id('tempdb.dbo.#New') is not null drop table #Master
create table #Master
(
    a varchar(10),
    b varchar(10),
    c varchar(10)
)

if object_id('tempdb.dbo.#new') is not null drop table #new
create table #new
(
    a varchar(10),
    b varchar(10),
    c varchar(10)
)

insert into #master
values ('a1', 'b1', null), ('a2', 'b2', null)

insert into #new
values ('a1', 'b1', 'c1'), ('a2', 'b2', 'c2')

Method 1: MERGE 方法1:合并

    merge into #master t -- target
using #new s --source
    on t.a = s.a
        and t.b = s.b
        and t.c = s.c
when not matched by target then insert
    (
        a,
        b,
        c
    )
    values
    (
        s.a,
        s.b,
        s.c
    )
when matched then update
    set c = s.c;

Method 2: Explicit Transaction 方法2:显式事务

begin tran

    update t
    set c = s.c
    from #master t -- target
    inner join #new s -- source
        on t.a = s.a
            and t.b = s.b
            and t.c = s.c

    insert into #master
    (
        a,
        b,
        c
    )
    select
        s.a,
        s.b,
        s.c
    from #new s -- source
    left outer join #master t --target
        on s.a = t.a
            and s.b = t.b
            and s.c = t.c
    where t.a is null

commit tran

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM