[英]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
语句以在单个查询中执行INSERT
, UPDATE
或DELETE
操作。
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.