使用SQL Server 2012.我想在表中插入唯一的字符串。我总是希望返回唯一字符串的行ID。现在,这可以通过两种方式实现。
哪种解决方案最好?
这是有问题的表格:
CREATE TABLE [dbo].[Comment](
[CommentID] [int] IDENTITY(1,1) NOT NULL,
[Comment] [nvarchar](256) NOT NULL
CONSTRAINT [PK_Comment] PRIMARY KEY CLUSTERED([CommentID] ASC)
)
CREATE UNIQUE NONCLUSTERED INDEX [IX_Comment_Comment] ON [dbo].[Comment]
(
[Comment] ASC
)
解决方案1 :
SELECT
首先检查字符串是否存在。如果是,请返回ID
。否则,INSERT
新行并返回新创建的ID
。
CREATE PROCEDURE [dbo].[add_comment]
@Comment [nvarchar](256)
AS
BEGIN
SET NOCOUNT ON
DECLARE @CommentID [int]
DECLARE @TransactionCount [int]
BEGIN TRY
SET @TransactionCount = @@TRANCOUNT
IF @TransactionCount = 0
BEGIN TRANSACTION
SELECT @CommentID = [CommentID] FROM [dbo].[Comment] WHERE [Comment] = @Comment
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO [dbo].[Comment]([Comment]) VALUES (@Comment)
SET @CommentID = SCOPE_IDENTITY()
END
IF @TransactionCount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND @TransactionCount = 0
ROLLBACK TRANSACTION
; THROW
END CATCH
RETURN @CommentID
END
解决方案2 :
首先 INSERT
。如果插入内容违反UNIQUE INDEX
,则会发出SELECT
。
CREATE PROCEDURE [dbo].[add_comment2]
@Comment [nvarchar](256)
AS
BEGIN
SET NOCOUNT ON
DECLARE @CommentID [int]
BEGIN TRY
INSERT INTO [dbo].[Comment]([Comment]) VALUES (@Comment)
SET @CommentID = SCOPE_IDENTITY()
END TRY
BEGIN CATCH
IF @@ERROR = 2601 -- Duplicate
SELECT @CommentID = [CommentID] FROM [dbo].[Comment] WHERE [Comment] = @Comment
ELSE
THROW
END CATCH
RETURN @CommentID
END
GO
解决方案3 :
想法? :)
答案 0 :(得分:5)
在我的测试中,我发现首先检查违规而不是让SQL Server尝试失败更有效率,尤其是当预计失败率很高时(并且最好它们的性能大致相同) ,当故障率低时)。详情here和here。
除了性能之外,不依赖于约束来引发错误的另一个原因是明天有人可能会改变或丢弃它。
答案 1 :(得分:1)
就我个人而言,这样做
INSERT INTO [dbo].[Comment]([Comment])
SELECT T.Comment
FROM (SELECT @Comment) T (Comment)
LEFT JOIN dbo.Comment C ON C.Comment = T.Comment
WHERE C.Comment IS NULL
SELECT @CommentID = CommentID
FROM dbo.Comment C
WHERE C.Comment = @Comment
答案 2 :(得分:1)
您还应该在事务中封装它。我喜欢条件插入的想法。
答案 3 :(得分:1)
我认为这是最简单的选择:
SET NOCOUNT ON;
BEGIN TRAN
/* Insert if doesn't already exist */
INSERT INTO dbo.comment (comment)
SELECT @comment
WHERE NOT EXISTS (
SELECT comment
FROM dbo.comment
WHERE comment = @comment
);
/* Return comment id */
SELECT commentid
FROM dbo.comment
WHERE comment = @comment;
END TRAN
如果您更喜欢较新的MERGE
语法(请先由Aaron Bertrand read this article ),请选择插入部分:
...
; WITH source AS (
SELECT @comment As comment
)
MERGE INTO dbo.comment As destination
USING source
ON source.comment = destination.comment
WHEN NOT MATCHED THEN
INSERT (comment)
VALUES (source.comment)
;
...
答案 4 :(得分:-2)
我会首先使用insert然后获取结果。 db将在内部进行检查。无论如何,您需要编写重复键的逻辑,因此请使用它。这样你就可以对数据库进行1次调用而不是2次。另外,谁知道2次调用之间会发生什么?
编辑:根据Aaron Bertrand的运行结果 - 这个答案并不总是有效。