Сброс SCOPE_IDENTITY () - PullRequest
       1

Сброс SCOPE_IDENTITY ()

7 голосов
/ 31 декабря 2010

У меня есть хранимая процедура, которая сначала вставляет некоторые данные во временную таблицу, а затем вставляет строку в другую таблицу.Я вызываю Scope_Identity () после второй вставки, чтобы забрать вновь вставленную идентификацию записи.

Если вторая вставка ничего не делает из-за объединения, я хочу проверить Scope_Identity и вызвать исключение.Но Scope_Identity возвращает последний идентификатор, созданный из вставки временной таблицы перед второй вставкой.

Есть ли способ сбросить SCOPE_IDENTITY перед вызовом второй вставки или лучший способ определить, не была ли вторая вставкана самом деле вставить что-нибудь?

Ответы [ 4 ]

10 голосов
/ 31 декабря 2010

Отметьте @@ROWCOUNT сразу после 2-й вставки. Если это 0, то ни одна строка не была вставлена.

INSERT INTO YourTable
SELECT ...

IF (@@ROWCOUNT = 0)
BEGIN
RAISERROR('Nothing inserted',16,1)
RETURN
END
5 голосов
/ 29 июня 2013

@ Мартин Смит полностью отвечает на ваш вопрос (я проголосовал за него).

По-видимому, это единственная страница в Интернете, спрашивающая, как сбросить Scope_Identity ().
Я считаю, что это жизненно важно для всех, кто работает с T-SQL.

Я оставляю этот ответ для всех, кто пришел сюда (как и я) в поисках идентификатора, который был вставлен предыдущим оператором вставки (и , а не последней случайно вставленной идентификационной вставкой).

Вот что я придумал:

SET @SomeID = (CASE WHEN @@ROWCOUNT > 0 THEN SCOPE_IDENTITY() ELSE NULL END)
0 голосов
/ 26 января 2017

Рассмотрев несколько вариантов, мне нравится рифф на @ ответ БенТула на связанный вопрос :

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, который помог бы мне понять, была ли вставлена ​​строка (в этом случае я хотел получить ее идентификатор) или нет , (Я бы не рекомендовал быть в этой ситуации в первую очередь, если это возможно!) То, что вы будете делать с @result, зависит от того, что вам нужно сделать.

Мне нравится, что отношения между INSERT и @result являются явными и вряд ли будут загрязнены другими промежуточными операциями, о которых я, возможно, не думаю. Мне также нравится, что @result, естественно, обрабатывает дела с несколькими вставленными строками.

0 голосов
/ 26 января 2017

Я думаю, что другие ответы могут быть более практичными, но я действительно хотел записать свои результаты здесь, на случай, если они кому-нибудь помогут. (Это в SQL Server 2005; не уверен, сохраняется ли это поведение в более новых версиях.)

В основе этого трюка лежит использование следующего свойства (из документации @@IDENTITY в Books Online): «После выполнения оператора 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...