1

给定一个表格,例如:

CREATE TABLE dbo.MyTestData (testdata varchar(50) NOT NULL) 

ALTER TABLE dbo.MyTestData WITH NOCHECK ADD CONSTRAINT [PK_MyTestData] PRIMARY KEY  CLUSTERED (testdata) 

并且假设当我们完成收集要从具有已知重复项的外部数据列表中添加的项目时,我们想要一个唯一的“testdata”列表......在执行插入存储过程时,应该编写该过程来测试是否存在或应该它只允许错误吗?最常见的做法是什么?我一直在进行存在性测试,但昨晚还在争论这个……

CREATE PROCEDURE dbo.dmsInsertTestData @ptestdata VarChar(50)
AS
  SET NOCOUNT ON

  IF NOT EXISTS(SELECT testdata FROM dbo.MyTestData WHERE testdata=@ptestdata)
  BEGIN
    INSERT INTO dbo.MyTestData (testdata ) VALUES (@ptestdata)
  END

RETURN 0

还是在执行此错误时捕获/忽略 PK 违规错误?

CREATE PROCEDURE dbo.dmsInsertTestData @ptestdata VarChar(50)
AS
  SET NOCOUNT ON
  INSERT INTO dbo.MyTestData (testdata ) VALUES (@ptestdata)
RETURN 0
4

6 回答 6

3

您的错误检查(即“IF NOT EXISTS ...”)可能会或可能不会起作用,因为存在潜在的竞争条件(如果另一个事务在您的 IF NOT EXISTS 语句之后但在您的 INSERT 语句之前插入记录)。

因此,无论您之前是否检查过,您都应该对 INSERT 语句进行编码,就好像它可能会失败一样。

您是否也想检查(不是,而是)取决于您和您的 UI。

于 2009-01-04T20:34:41.057 回答
2

我总是在一个声明中做到这一点:

INSERT INTO dbo.MyTestData (testdata ) VALUES (@ptestdata)
WHERE NOT EXISTS(SELECT 1 FROM dbo.MyTestData WHERE testdata=@ptestdata)
于 2009-01-04T20:37:39.180 回答
0

我认为大多数程序员会建议避免异常。从 T-SQL 的性能角度来看,我不确定,但在 .NET 中,我相信抛出的异常比附加的 if/else 语句成本更高。

于 2009-01-04T20:12:10.633 回答
0

我对您给出的第一个示例的担忧是它没有向用户返回错误。可以修复它,但除非它返回错误,否则我不会使用它。

如果您对这两种可能性的担忧是在大型表上的性能,我建议您同时测试它们,看看其中一个是否明显快于另一个。如果 if 选择特别复杂,并且插入将需要在大多数情况下发生,那么在大多数情况下,简单地让它失败可能会更快。另一方面,如果输入错误的可能性很高,并且 if 相对简单,如此处所示,那么另一个过程可能是一个更好的过程。但是只有对您的真实数据结构和数据以及您的真实查询进行真实测试才能告诉您哪个性能更好,因为它可能在不同的情况下有所不同。

于 2009-01-04T20:22:25.060 回答
0

我相信这取决于存储过程的性质。基本上,如果您与它们有关(或为程序的客户封装它们),则应该处理错误,如果您与它们没有任何关系并且不能使其对其他人更友好,则让它们传播应用层。

如果存储过程旨在插入原始数据,我认为它应该让应用程序来处理可能的错误。如果存储过程被设计为一个抽象层(并且执行特定任务而不是运行特定语句)并且可以处理错误并对其执行某些操作或者可以以优雅的方式报告它(例如,明确定义错误代码)到应用程序,它应该这样做。否则,应该由应用程序确保它没有插入重复数据,而不是数据库(数据库已经使用主键强制执行此操作)。

于 2009-01-04T20:23:22.563 回答
0

为了用户友好,执行 SELECT 通常是一个好习惯,如果记录已经存在,则为用户提供查看和/或编辑它的机会。

例如,如果用户正在添加新的客户记录,他们可能想要查看已为该客户显示的信息。他们可能有其他信息要添加到记录中,例如电话号码。

在这种情况下,拒绝添加记录不如提供查看现有副本的能力有用。

于 2009-01-04T20:25:49.670 回答