重置SCOPE_IDENTITY()

时间:2010-12-31 19:19:56

标签: sql-server tsql stored-procedures

我有一个存储过程,首先将一些数据插入临时表,然后将一行插入另一个表。我在第二次插入后调用Scope_Identity()来获取新插入的记录标识。

如果第二个插入因连接而不执行任何操作,我想检查Scope_Identity并引发异常。但Scope_Identity返回在第二次插入之前从临时表插入创建的最后一个标识。

有没有办法在调用第二个插入之前重置SCOPE_IDENTITY,或者更好的方法来确定第二个插入是否实际上没有插入任何内容?

4 个答案:

答案 0 :(得分:10)

在第二次插入后立即检查@@ROWCOUNT 。如果为0则不插入任何行。

INSERT INTO YourTable
SELECT ...

IF (@@ROWCOUNT = 0)
BEGIN
RAISERROR('Nothing inserted',16,1)
RETURN
END

答案 1 :(得分:5)

@Martin Smith完全回答了你的问题(我赞成他)。

这显然是互联网上唯一一个询问如何重置Scope_Identity()的页面 我相信这对使用T-SQL的人来说至关重要。

我将这个答案留给那些来到这里的人(像我一样)寻找前一个插入语句所插入的身份(并且不是最后一个随机成功的身份插入)。
/> 这就是我想出的:

SET @SomeID = (CASE WHEN @@ROWCOUNT > 0 THEN SCOPE_IDENTITY() ELSE NULL END)

答案 2 :(得分:0)

我认为给出的其他答案可能更实用,但我确实想在这里记录我的发现,以防某些人某天有所帮助。 (这是在SQL Server 2005中;不确定在新版本中此行为是否仍然存在。)

该技巧的基础是利用以下属性(来自联机丛书&@@IDENTITY的文档):"完成INSERT,SELECT INTO或批量复制语句之后。 。 。如果该语句不影响任何具有标识列的表,则@@ IDENTITY将返回NULL。"虽然我无法明确说明,但这种行为似乎也适用于SCOPE_IDENTITY()。因此,我们完成了INSERT语句,该语句不会影响具有标识列的任何表:

CREATE TABLE NoIdentity (notId BIT NOT NULL)

-- An insert that actually inserts sets SCOPE_IDENTITY():
INSERT INTO YourTable (name)
SELECT 'a'
WHERE 1 = 1 -- simulate a join that yields rows

SELECT @@identity, SCOPE_IDENTITY()
-- 14, 14 (or similar)

-- The problem: an insert that doesn't insert any rows leaves SCOPE_IDENTITY() alone.
INSERT INTO YourTable (name)
SELECT 'a'
WHERE 1 = 0 -- simulate a join that yields no rows

SELECT @@identity, SCOPE_IDENTITY()
-- Still 14, 14 . . . how do we know we didn't insert any rows?

-- Now for the trick:
INSERT INTO NoIdentity (notId)
SELECT 0
WHERE 1 = 0 -- we don't actually need to insert any rows for this to work

SELECT @@identity, SCOPE_IDENTITY()
-- NULL, NULL.  Magic!

INSERT INTO YourTable (name)
SELECT 'a'
WHERE 1 = 0 -- simulate a join that yields no rows

SELECT @@identity, SCOPE_IDENTITY()
-- Still NULL, NULL since we didn't insert anything.  But if we had, it would be non-NULL.
-- We can tell the difference!

所以,对于你的情况,似乎你可以做到

INSERT INTO NoIdentity (notId)
SELECT 0
WHERE 1 = 0

在执行第二次SCOPE_IDENTITY()之前重置INSERT

答案 3 :(得分:0)

考虑了几种选择,我发现自己喜欢@BenThul's answer to a related question上的即兴演奏:

DECLARE @result TABLE (id INT NOT NULL)

INSERT INTO YourTable (name)
OUTPUT INSERTED.id INTO @result (id)
SELECT 'a'
WHERE 1 = 0 -- simulate a join result

SELECT CASE
    WHEN (SELECT COUNT(1) FROM @result) = 1 THEN (SELECT TOP 1 id FROM @result)
    ELSE -1
END

从我的最终SELECT CASE...可以看出,在我的情况下,我试图找到一个INT NOT NULL来帮助我理解是否插入了一行(在这种情况下我想要它ID)与否。 (如果可能的话,我不建议首先处于这种情况!)你对@result的处理取决于你需要做什么。

我喜欢INSERT@result之间的关系是明确的,不太可能被我可能不会考虑的其他干预操作所污染。我也喜欢@result自然处理插入多行的情况。