简体   繁体   English

与主键冲突合并

[英]Merge with primary key violation

I have a file based import thingy where the users can post files to be imported in the database. 我有一个基于文件的导入内容,用户可以在其中发布要导入数据库中的文件。 New records are inserted and records with an already existing Id are updated. 将插入新记录,并更新具有现有ID的记录。

After posting a file with ID NAME 5 Silly 发布ID为NAME 5 Silly的文件后

they can correct this by posting a new file with ID NAME 5 Sally 他们可以通过发布ID为NAME 5 Sally的新文件来更正此问题

I have a bulk insert (C# windows service) of the file into a bulk table (Sql Server Azure v12). 我将文件的批量插入(C#Windows服务)插入了批量表(Sql Server Azure v12)。 The files can contain millions of rows so I'd like to avoid iterating through rows. 这些文件可以包含数百万行,因此我想避免遍历行。 After the bulk insert i have a SP that does a merge update / insert and updates already existing rows and inserts new ones. 批量插入后,我有一个SP进行合并更新/插入并更新已经存在的行并插入新行。

The problem I've come across is when the users post a new record and a correction of the same record in the same file. 我遇到的问题是,当用户发布新记录并更正同一文件中的同一记录时。 I get a PRIMARY KEY VIOLATION on the target table. 我在目标表上收到主键冲突。

Is there a nice way to solve this? 有解决这个问题的好方法吗?

Here's an example: 这是一个例子:

--drop table #bulk --drop table #target create table #bulk( id int, name varchar(10) )

insert into #bulk values (1,'John') insert into #bulk values (2,'Sally') insert into #bulk values (3,'Paul') insert into #bulk values (4,'Gretchen') insert into #bulk values (5,'Penny') insert into #bulk values (5,'Peggy') create table #target( id int not null, name varchar(10), primary key (id))

insert into #bulk values (1,'John') insert into #bulk values (2,'Sally') insert into #bulk values (3,'Paul') insert into #bulk values (4,'Gretchen') insert into #bulk values (5,'Penny') insert into #bulk values (5,'Peggy') create table #target( id int not null, name varchar(10), primary key (id))

merge #target as target using(select id, name from #bulk) as bulktable on target.id = bulktable.id when matched then update set target.name = bulktable.name when not matched then insert(id, name) values (bulktable.id, bulktable.name);

This will handle the latest value for name. 这将处理名称的最新值。

You need a new create script for #bulk 您需要一个用于#bulk的新创建脚本

CREATE TABLE #bulk
(
  row_id int identity(1,1),
  id int,
  name varchar(10)
)

This is the script you can use with the new bulk table: 这是可以与新批量表一起使用的脚本:

;WITH CTE as
(
  SELECT
    id, name, 
    row_number() over (partition by id order by row_id desc) rn
    FROM #bulk
), CTE2 as
(
  SELECT id, name
  FROM CTE
  WHERE rn = 1
)
MERGE #target as target
USING CTE2 as bulktable
on target.id = bulktable.id
WHEN matched and 
 not exists(SELECT target.name except SELECT bulktable.name)
 -- this will handle null values. Otherwise it could simply have been: 
 -- matched and target.name <> bulktable.name
THEN update
SET target.name = bulktable.name
WHEN not matched THEN
INSERT(id, name) VALUES (bulktable.id, bulktable.name);

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

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