如何使用最少的操作在SQL Server 2012中"插入或选择"?

cru*_*ush 3 t-sql sql-server sql-server-2012

我一直在寻找类似于此问题的问题,我现在还没有找到任何东西,所以如果以前曾经问过这个问题,那至少可以作为那些对正确命名法无知的人的指针.

INSERT INTO基于唯一键,如果一行尚不存在,我想要一个表.它确实存在,然后我想获得该行的主键ID.

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

EmailAddressId(PK) | EmailAddress(UK)
Run Code Online (Sandbox Code Playgroud)

我想在INSERT该表中添加一个新的电子邮件地址,但是有一个独特的约束条件EmailAddress.因此,如果新的电子邮件地址与现有电子邮件地址相同,INSERT则将失败.在那种情况下,我想EmailAddressId从数据库中选择现有的EmailAddress.

我想在最少的操作中执行此操作,假设碰撞将是罕见的情况.

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

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
Run Code Online (Sandbox Code Playgroud)

上面的代码起作用,并产生所需的结果,但互联网让我觉得TRY...CATCH以这种方式使用可能会很慢......因此我不确定这是否是最佳解决方案.

我只找到了另一个解决方案,SELECT第一个和INSERT第二个.这几乎在所有时间都会导致2次操作,因为我预计很少有重复的电子邮件地址(至少一个月或更长时间).

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

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

Qua*_*noi 5

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
;
Run Code Online (Sandbox Code Playgroud)

  • 您可以改为更新虚拟局部变量. (2认同)