我一直在寻找与此类似的问题,但我还没有找到任何东西,所以如果之前有人问过这个问题,这至少可以为那些无知的人提供一个很好的指导正确的命名法。
如果某行尚不存在,我想根据唯一键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 次操作,因为我预计重复的电子邮件地址很少(至少一个月或更长时间)。
- 这是实现对
INSERT
的 1 次操作和对 INSERT
的 2 次操作失败的最佳解决方案吗? - 还有哪些其他解决方案可以实现对
INSERT
的 1 操作和 2INSERT
操作失败?
如果我误用了任何术语,请更正。
最佳答案
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/