多行的唯一约束..如何在不停止所有行的情况下不插入重复项
Unique constraint on multiple rows..how just not insert duplicate without stopping all
我有一个 table,我正在尝试向其中添加以下约束,以避免在插入约束列的副本时出现重复,但我不确定如何让它不失败如果插入多行,则完全插入重复插入尝试。
这是我要添加的约束:
BEGIN
IF NOT EXISTS (SELECT * FROM sys.tables where name = N'T_1321_PNAnnotationCommitReport')
BEGIN
CREATE TABLE AnnotationCommitReport (
[id] [INT] IDENTITY(1,1) PRIMARY KEY not null, --key
[progressnote_id] [INT] NOT NULL,
[form_id] [INT] NOT NULL,
[question_id] [INT],
[question_value] [VARCHAR](max),
[associatedconcept_id] [INT],
[OI_create_date] [DATETIME], --SCHED_RPT_DATE
[crte_date] [DATETIME] DEFAULT CURRENT_TIMESTAMP,
);
--create unique constraint on indicated columns to prevent dups inserted
ALTER TABLE AnnotationCommitReport
ADD CONSTRAINT PN_Unique UNIQUE (progressnote_id, form_id, question_id, question_value, associatedconcept_id, OI_create_date)
END
这是我向其中添加可以复制的行的地方:
INSERT INTO AnnotationCommitReport(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT progressnote_id,
form_id,
question_id,
questionvalue,
concept_id,
create_date as OI_create_date,
getdate()
FROM FORM_QUESTION
WHERE
(create_date > @LAST_RUN_DATE
AND
create_date <= @RUN_TO_DATE)
END --it's much more complicated than this, so I simplified for this example
如何让它不插入重复的行?有人建议 try/catch,但我认为如果在重复行之后有要插入的行,它会阻止插入剩余部分。我找到了 ,但我不确定它是否可以使用,我也不确定他们在谈论什么地图以及如何将其应用到我所拥有的东西中。
更新:这里是最后一个插入的详细信息,比我最初提供的要多:
INSERT INTO dbo.AnnotationCommitReport(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT progressnote_id,
a.form_id,
question_id,
questionvalue,
fq.concept_id,
a.create_date as OI_create_date,
getdate()
FROM (
SELECT form_id,
progressnote_id,
R.Q.value('@id', 'varchar(max)') AS questionid,
R.Q.value('@value', 'varchar(max)') AS questionvalue,
t.create_date
FROM
@tableNotes t
OUTER APPLY t.form_questions.nodes('/RESULT/QUESTIONS/QUESTION') AS R(Q)
WHERE
ISNUMERIC(R.Q.value('@id', 'varchar(max)')) <> 0
) a
INNER JOIN [CKOLTP_DEV]..FORM_QUESTION fq ON
fq.form_id = a.form_id AND
fq.question_id = a.questionid
WHERE
(a.create_date > @LAST_RUN_DATE
AND
a.create_date <= @RUN_TO_DATE)
How do I make it just not insert that duplicate row?
对唯一索引使用 MERGE instead of INSERT so you can check for duplicates and only insert when the new row is NOT MATCHED at the target, or set the IGNORE_DUP_KEY 选项。
为什么不将插入语句写成 select 语句,以便使用 where 条件过滤掉重复项。
有一个这种方法的例子(虽然显然不是完全相同的问题),但看到这个:Avoid duplicates in INSERT INTO SELECT query in SQL Server
在您的情况下,这将涉及在 AnnotationCommitReport 和插入之间进行连接 select,以避免重复。
这就是我按照@Menios 的建议所做的事情
--I created a temp table with what I intend to put in DB table
INSERT INTO @pnAnnotationCommitReport_ToBeInserted(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT progressnote_id,
a.form_id,
question_id,
questionvalue,
fq.concept_id,
a.create_date as OI_create_date,
getdate()
FROM (
SELECT form_id,
progressnote_id,
R.Q.value('@id', 'varchar(max)') AS questionid,
R.Q.value('@value', 'varchar(max)') AS questionvalue,
t.create_date
FROM
@tableNotes t
OUTER APPLY t.form_questions.nodes('/RESULT/QUESTIONS/QUESTION') AS R(Q)
WHERE
ISNUMERIC(R.Q.value('@id', 'varchar(max)')) <> 0
--AND
-- create_date > @LAST_RUN_DATE
) a
INNER JOIN [CKOLTP_DEV]..FORM_QUESTION fq ON
fq.form_id = a.form_id AND
fq.question_id = a.questionid
WHERE
(a.create_date > @LAST_RUN_DATE
AND
a.create_date <= @RUN_TO_DATE)
--AND NOT EXISTS(SELECT progressnote_id, a.form_id, question_id, a.questionvalue, fq.concept_id, a.create_date where pn.progressnote_id=a.progressnote_id, )
--Insert into main table, only values that aren't duplicated
INSERT INTO AnnotationCommitReport(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT
pni.progressnote_id
, pni.form_id
, pni.question_id
, pni.question_value
, pni.associatedconcept_id
, pni.OI_create_date
FROM @pnAnnotationCommitReport_ToBeInserted pni
WHERE NOT EXISTS
(SELECT progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date
FROM AnnotationCommitReport pn
WHERE
pni.progressnote_id=pn.progressnote_id
AND
pni.form_id=pn.form_id
AND
pni.question_id=pn.question_id
AND
pni.question_value=pn.question_value
AND
pni.associatedconcept_id=pn.associatedconcept_id
AND
pni.OI_create_date=pn.OI_create_date)
我有一个 table,我正在尝试向其中添加以下约束,以避免在插入约束列的副本时出现重复,但我不确定如何让它不失败如果插入多行,则完全插入重复插入尝试。
这是我要添加的约束:
BEGIN
IF NOT EXISTS (SELECT * FROM sys.tables where name = N'T_1321_PNAnnotationCommitReport')
BEGIN
CREATE TABLE AnnotationCommitReport (
[id] [INT] IDENTITY(1,1) PRIMARY KEY not null, --key
[progressnote_id] [INT] NOT NULL,
[form_id] [INT] NOT NULL,
[question_id] [INT],
[question_value] [VARCHAR](max),
[associatedconcept_id] [INT],
[OI_create_date] [DATETIME], --SCHED_RPT_DATE
[crte_date] [DATETIME] DEFAULT CURRENT_TIMESTAMP,
);
--create unique constraint on indicated columns to prevent dups inserted
ALTER TABLE AnnotationCommitReport
ADD CONSTRAINT PN_Unique UNIQUE (progressnote_id, form_id, question_id, question_value, associatedconcept_id, OI_create_date)
END
这是我向其中添加可以复制的行的地方:
INSERT INTO AnnotationCommitReport(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT progressnote_id,
form_id,
question_id,
questionvalue,
concept_id,
create_date as OI_create_date,
getdate()
FROM FORM_QUESTION
WHERE
(create_date > @LAST_RUN_DATE
AND
create_date <= @RUN_TO_DATE)
END --it's much more complicated than this, so I simplified for this example
如何让它不插入重复的行?有人建议 try/catch,但我认为如果在重复行之后有要插入的行,它会阻止插入剩余部分。我找到了
更新:这里是最后一个插入的详细信息,比我最初提供的要多:
INSERT INTO dbo.AnnotationCommitReport(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT progressnote_id,
a.form_id,
question_id,
questionvalue,
fq.concept_id,
a.create_date as OI_create_date,
getdate()
FROM (
SELECT form_id,
progressnote_id,
R.Q.value('@id', 'varchar(max)') AS questionid,
R.Q.value('@value', 'varchar(max)') AS questionvalue,
t.create_date
FROM
@tableNotes t
OUTER APPLY t.form_questions.nodes('/RESULT/QUESTIONS/QUESTION') AS R(Q)
WHERE
ISNUMERIC(R.Q.value('@id', 'varchar(max)')) <> 0
) a
INNER JOIN [CKOLTP_DEV]..FORM_QUESTION fq ON
fq.form_id = a.form_id AND
fq.question_id = a.questionid
WHERE
(a.create_date > @LAST_RUN_DATE
AND
a.create_date <= @RUN_TO_DATE)
How do I make it just not insert that duplicate row?
对唯一索引使用 MERGE instead of INSERT so you can check for duplicates and only insert when the new row is NOT MATCHED at the target, or set the IGNORE_DUP_KEY 选项。
为什么不将插入语句写成 select 语句,以便使用 where 条件过滤掉重复项。
有一个这种方法的例子(虽然显然不是完全相同的问题),但看到这个:Avoid duplicates in INSERT INTO SELECT query in SQL Server
在您的情况下,这将涉及在 AnnotationCommitReport 和插入之间进行连接 select,以避免重复。
这就是我按照@Menios 的建议所做的事情
--I created a temp table with what I intend to put in DB table
INSERT INTO @pnAnnotationCommitReport_ToBeInserted(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT progressnote_id,
a.form_id,
question_id,
questionvalue,
fq.concept_id,
a.create_date as OI_create_date,
getdate()
FROM (
SELECT form_id,
progressnote_id,
R.Q.value('@id', 'varchar(max)') AS questionid,
R.Q.value('@value', 'varchar(max)') AS questionvalue,
t.create_date
FROM
@tableNotes t
OUTER APPLY t.form_questions.nodes('/RESULT/QUESTIONS/QUESTION') AS R(Q)
WHERE
ISNUMERIC(R.Q.value('@id', 'varchar(max)')) <> 0
--AND
-- create_date > @LAST_RUN_DATE
) a
INNER JOIN [CKOLTP_DEV]..FORM_QUESTION fq ON
fq.form_id = a.form_id AND
fq.question_id = a.questionid
WHERE
(a.create_date > @LAST_RUN_DATE
AND
a.create_date <= @RUN_TO_DATE)
--AND NOT EXISTS(SELECT progressnote_id, a.form_id, question_id, a.questionvalue, fq.concept_id, a.create_date where pn.progressnote_id=a.progressnote_id, )
--Insert into main table, only values that aren't duplicated
INSERT INTO AnnotationCommitReport(progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date)
SELECT
pni.progressnote_id
, pni.form_id
, pni.question_id
, pni.question_value
, pni.associatedconcept_id
, pni.OI_create_date
FROM @pnAnnotationCommitReport_ToBeInserted pni
WHERE NOT EXISTS
(SELECT progressnote_id,form_id,question_id,question_value,associatedconcept_id, OI_create_date, crte_date
FROM AnnotationCommitReport pn
WHERE
pni.progressnote_id=pn.progressnote_id
AND
pni.form_id=pn.form_id
AND
pni.question_id=pn.question_id
AND
pni.question_value=pn.question_value
AND
pni.associatedconcept_id=pn.associatedconcept_id
AND
pni.OI_create_date=pn.OI_create_date)