sql-server - 如何使用最少的操作在 SQL Server 2012 中使用 "INSERT or SELECT"?

标签 sql-server tsql sql-server-2012

我一直在寻找与此类似的问题,但我还没有找到任何东西,所以如果之前有人问过这个问题,这至少可以为那些无知的人提供一个很好的指导正确的命名法。

如果某行尚不存在,我想根据唯一键INSERT INTO 一个表。它确实存在,那么我想获取该行的主键Id。

想象一个包含电子邮件地址的表:

EmailAddressId(PK) | EmailAddress(UK)

我想INSERT 到那个表中一个新的电子邮件地址,但是EmailAddress 有一个唯一的约束。因此,如果新电子邮件地址与现有电子邮件地址相同,INSERT 将失败。在这种情况下,我想从数据库中为 EmailAddress 选择现有的 EmailAddressId

我希望以最少的操作次数来执行此操作,假设碰撞很少见。

因此,我在存储过程中设置了一个 TRY...CATCH block ,如下所示:

ALTER PROCEDURE [dbo].[EmailAddressWrite]
    @EmailAddress nvarchar[256]
BEGIN
SET NOCOUNT ON;
    BEGIN TRANSACTION

    DECLARE @EmailAddressId INT

    BEGIN TRY
        INSERT INTO EmailAddress VALUES (@EmailAddress)
        SET @EmailAddressId = (SELECT SCOPE_IDENTITY())
    END TRY
    BEGIN CATCH
        SET @EmailAddressId = (SELECT EmailAddressId FROM EmailAddress WHERE EmailAddress = @EmailAddress)
    END CATCH

    --Do some more stuff with the Id now.

    COMMIT TRANSACTION

    RETURN @EmailAddressId
END

上面的代码运行并产生了所需的结果,但是互联网让我认为以这种方式使用 TRY...CATCH 可能会很慢...因此我不确定这是否是最优解。

我只找到了另一种解决方案,即先SELECT,再INSERT。这将导致几乎所有时间都进行 2 次操作,因为我预计重复的电子邮件地址很少(至少一个月或更长时间)。

  1. 这是实现对 INSERT 的 1 次操作和对 ​​INSERT 的 2 次操作失败的最佳解决方案吗?
  2. 还有哪些其他解决方案可以实现对 INSERT 的 1 操作和 2 INSERT 操作失败?

如果我误用了任何术语,请更正。

最佳答案

DECLARE @id INT

DECLARE @newid TABLE
        (
        emailAddressId INT NOT NULL PRIMARY KEY
        )

;
WITH    t AS
        (
        SELECT  *
        FROM    emailAddress WITH (ROWLOCK, HOLDLOCK)
        WHERE   emailAddress = @emailAddress
        )
MERGE
INTO    t
USING   (
        SELECT  @emailAddress
        ) s (emailAddress)
ON      1 = 1
WHEN NOT MATCHED BY TARGET THEN
INSERT  (emailAddress)
VALUES  (emailAddress)
WHEN MATCHED THEN
UPDATE
SET     @id = 1
OUTPUT  INSERTED.emailAddressId
INTO    @newid
;

关于sql-server - 如何使用最少的操作在 SQL Server 2012 中使用 "INSERT or SELECT"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31126488/

相关文章:

sql - 波斯语全文索引停止列表

sql - 使用动态 SQL 获取各种错误

.net - 时间:2019-05-08 标签:c#sslexception : SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL

sql - 将数据从数据库插入到另一个数据库

sql-server-2008 - 快速更新插入 Sql server 2008 R2

sql-server - 执行存储过程时使用函数作为参数?

sql - 两个 select 语句的求和结果

sql-server - EF Core SQL Server 使用 GETDATE() 代替 C# DateTime.Now

sql - 如何从 Visual Studio 2013 或 2010 中的解决方案资源管理器运行 sql 脚本

sql-server - 从外部 ip 启用 sql server 连接