有一篇文章here说这是一个坏主意,而不是使用唯一约束,我必须始终INSERT
只有数据不在数据库中。现在我的表结构如下:
CREATE TABLE [dbo].[TEST](
[ColA] [varchar](255) NULL,
[ColB] [datetime] NULL,
[ColC] [datetime] NULL,
[ColD] [int] NOT NULL,
) ON [PRIMARY]
对于我来说,只需要唯一的行,因此在设置唯一约束时有意义:
ALTER TABLE dbo.TEST
ADD CONSTRAINT uniqueRows UNIQUE (ColA, ColB, ColC, ColD) WITH (IGNORE_DUP_KEY = ON)
当消耗新信息时,由于许多原因,可能会处理重复数据,因为我的代码不维护状态,因此至少对我来说忽略任何重复数据是有意义的。
然而,在他linked post的answer,@ PhilipKelley中,他说这是一个坏主意,应该按照以下方式进行检查:
INSERT INTO X
VALUES(Y,Z)
WHERE Y NOT IN (SELECT Y FROM X)
在我的情况下转换为:
INSERT INTO dbo.TEST
VALUES(ValA,ValB,ValC,ValD)
WHERE (Some complicated check)
或者也许制作一些花哨的主键。响应here暗示如果我知道这确实被用作一个功能,我可以继续使用IGNORE_DUP_KEY
选项,一切都会好的。在我的案例中建议的路径是什么?
答案 0 :(得分:1)
我个人认为你应该做三件事:
对于单行插入,这可以简单如下:
BEGIN TRY
INSERT dbo.TEST(ValA, ValB, ValC, ValD)
SELECT @ValA, @ValB, @ValC, @ValD
WHERE NOT EXISTS
(SELECT 1 FROM dbo.TEST
WHERE ValA = @ValA AND ValB = @ValB AND ValC = @ValC AND ValD = @ValD);
END TRY
BEGIN CATCH
PRINT 'Move along, nothing to see here...';
END CATCH
如果这些列中的任何一个或所有列都可以为空,那就会变得复杂一些。
对于多行插入,您可以通过多种方式处理此问题。如果存在非唯一值(单独使用批处理或与表冲突),则可以使整个批处理失败,或者只允许成功的行进入表中。情况A:
IF EXISTS (SELECT 1 FROM @SourceOfMultipleRows AS r
WHERE EXISTS (SELECT 1 FROM dbo.Test AS t WHERE t.ValA = r.ValA AND ...))
OR EXISTS (SELECT 1 FROM @SourceOfMultipleRows
GROUP BY ValA, ValB, ValC, ValD HAVING COUNT(*) > 1)
BEGIN
PRINT 'Not proceeding at all.';
END
ELSE
BEGIN
BEGIN TRY
INSERT dbo.TEST(ValA, ValB, ValC, ValD)
SELECT ValA, ValB, ValC, ValD
FROM @SourceOfMultipleRows AS r
WHERE NOT EXISTS (SELECT 1 FROM dbo.Test AS t
WHERE t.ValA = r.ValA AND ...)
GROUP BY ValA, ValB, ValC, ValD;
END TRY
BEGIN CATCH
PRINT 'Move along, nothing to see here...';
END CATCH
END
方案B,您希望保留好行并忽略重复项:
BEGIN TRY
INSERT dbo.TEST(ValA, ValB, ValC, ValD)
SELECT ValA, ValB, ValC, ValD
FROM @SourceOfMultipleRows AS r
WHERE NOT EXISTS (SELECT 1 FROM dbo.Test AS t
WHERE t.ValA = r.ValA AND ...)
GROUP BY ValA, ValB, ValC, ValD;
END TRY
BEGIN CATCH
PRINT 'Move along...';
END CATCH