【问题标题】:check value does not already exist in a column before inserting new record在插入新记录之前检查值不存在于列中
【发布时间】:2019-07-24 08:38:55
【问题描述】:

我有一个有两列的表格。

第一列是主键,SQL自动生成值。

当向我的表 myTbl 中插入一条新记录时,我想确保 ExternalId 值当前不存在于我的表中。

我正要创建一个插入触发器,但认为可能有比创建触发器更好/更有效的方法?

create table myTbl
(
    TeamId int not null identity(1000, 1),
    ExternalId nvarchar(14)
    constraint PK_myTbl primary key(TeamId)
)


     TeamId     ExternalId
     1000       DFJK
     1001       LMKG
     1002       PLKM

【问题讨论】:

标签: sql sql-server sql-server-2016


【解决方案1】:

一个简单的选择是在ExternalId 列上添加唯一约束:

ALTER TABLE myTbl ADD CONSTRAINT cnstr_ext UNIQUE(ExternalId);

然后任何尝试插入包含 ExternalId 值且已存在于表中的新记录都会导致错误。

如果您使用 Java 或 C# 等应用程序语言进行此插入,您的代码中会出现异常,您可以根据需要进行处理。

【讨论】:

    【解决方案2】:

    如果您不执行 RBAR 插入,那么有几个选项。哪个工作最快将取决于您的数据的形状。下面的两个选项通过测试来查看值是否已经在表中,或者将两个表合并在一起。我已经包含了合并,因为它有时可以在一个命令中添加或更新行。

    关于合并命令的很好的文档可以广泛使用。

    IF OBJECT_ID('tempdb..#myTbl') IS NOT NULL DROP TABLE #myTbl;
    
    DECLARE @values_to_add_1 TABLE (ExternalId NVARCHAR(14));
    
    DECLARE @values_to_add_2 TABLE (ExternalId NVARCHAR(14));
    
    CREATE TABLE #myTbl (TeamId     INT NOT NULL IDENTITY(1000, 1)
    ,                    ExternalId NVARCHAR(14)
                             CONSTRAINT PK_myTbl
                             PRIMARY KEY (TeamId));
    
    INSERT INTO #myTbl (ExternalId)
    VALUES ('DFJK')
    ,      ('LMKG')
    ,      ('PLKM');
    
    INSERT INTO @values_to_add_1
    VALUES ('DFJK'), ('1234');
    
    INSERT INTO @values_to_add_2
    VALUES ('LMKG'), ('5678');
    
    SET STATISTICS IO, TIME ON;
    
    INSERT INTO #myTbl (ExternalId)
    SELECT  ExternalId
      FROM  @values_to_add_1 VTA
     WHERE  NOT EXISTS (SELECT  1 FROM  #myTbl MT WHERE MT.ExternalId = VTA.ExternalId);
    
    MERGE #myTbl Target
    USING (SELECT   * FROM  @values_to_add_2) Source
       ON Target.ExternalId = Source.ExternalId
     WHEN NOT MATCHED BY TARGET THEN INSERT (ExternalId)
                                     VALUES (Source.ExternalId);
    
    SET STATISTICS IO, TIME OFF;
    
    SELECT * FROM #myTbl
    

    如果您一次只添加一行,那么根据您希望重复多少次,“请求宽恕比许可更好”的方法可能会更快。如果您编写 RBAR 并抛出错误不会停止您的代码,那么该约束只会产生很小的开销。

    【讨论】:

      【解决方案3】:

      您有 2 个选项,要么在表上使用唯一约束,要么在每次插入之前使用 sql 语句检查。

      由于第二个选项效率低得多并且有几个问题,我建议第一个选项。

      alter table myTbl add constraint UX_ExternalId unique(ExternalId);
      

      现在您可以将插入内容放在try ... catch 中,并且您只需要在发生错误时采取措施

      第二个选项有几个问题:

      • 检查语句和插入需要在同一个 交易

      • check语句必须每次都做,没有重复的时候也要做,效率很低

      • 如果有人尝试用其他软件插入,不保证他也会做这个检查

      【讨论】:

      • 请注意,如果检查和插入都发生在单个可序列化事务中,则第二个选项在逻辑上是合理的。
      猜你喜欢
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-19
      • 2021-08-18
      • 1970-01-01
      相关资源
      最近更新 更多