我有一个存储过程,首先将一些数据插入临时表,然后将一行插入另一个表。我在第二次插入后调用Scope_Identity()来获取新插入的记录标识。
如果第二个插入因连接而不执行任何操作,我想检查Scope_Identity并引发异常。但Scope_Identity返回在第二次插入之前从临时表插入创建的最后一个标识。
有没有办法在调用第二个插入之前重置SCOPE_IDENTITY,或者更好的方法来确定第二个插入是否实际上没有插入任何内容?
答案 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
自然处理插入多行的情况。