2010-12-31 11 views
7

Mam procedura składowana, która najpierw wstawia niektóre dane do tabeli temp, a następnie wstawia wiersz do innej tabeli. Wywołuję Scope_Identity() po drugiej wstawce, aby pobrać nowo wstawioną Tożsamość rekordu.Resetuj SCOPE_IDENTITY()

Jeśli druga wstawka nic nie robi z powodu złączenia, chcę sprawdzić właściwość Scope_Identity i zgłosić wyjątek. Ale Scope_Identity zwraca ostatnią tożsamość utworzoną z wstawienia tabeli temp przed drugą wstawką.

Czy istnieje sposób na zresetowanie SCOPE_IDENTITY przed wywołaniem drugiej wstawki lub lepszy sposób na sprawdzenie, czy druga wstawka w rzeczywistości niczego nie wstawiła?

Odpowiedz

9

Po otrzymaniu drugiej wkładki należy od razu sprawdzić @@ROWCOUNTpod numerem. Jeśli ma wartość 0, to nie wstawiono żadnych wierszy.

INSERT INTO YourTable 
SELECT ... 

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

@Martin Smith całkowicie odpowiada na twoje pytanie (przegłosowałem go).

Jest to najwyraźniej jedyna strona w Internecie z pytaniem, jak zresetować Scope_Identity().
Wierzę, że jest to niezbędne dla każdego, kto pracuje z T-SQL.

Pozostawiam tę odpowiedź każdemu, kto tu przybył (tak jak ja), szukając tożsamości, która została wstawiona przez poprzednią instrukcję wstawiania (i nie ostatnia losowo wybrana wstawka tożsamości).

To właśnie wymyśliłem:

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

Myślę inne odpowiedzi udzielone może być bardziej praktyczne, ale ja chciałem nagrać moje odkrycie tutaj w przypadku pomaga ktoś kiedyś. (Jest to w SQL Server 2005, nie ma pewności, czy to zachowanie będzie występować w nowszych wersjach.)

Podstawą triku jest wykorzystanie następującej właściwości (z dokumentacji Books Online z @@IDENTITY): "Po INSERT, WYBIERZ Instrukcja INTO lub zbiorczego kopiowania została zakończona ... Jeśli instrukcja nie wpłynęła na tabele z kolumnami tożsamości, @@ IDENTITY zwraca NULL. " Chociaż nie mogę znaleźć tego wprost, wydaje się, że to zachowanie dotyczy również SCOPE_IDENTITY(). Więc wypełnić oświadczenie INSERT że nie narusza żadnych tabel z kolumnami tożsamości:

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! 

tak, w Twoim przypadku, wydaje się, że można zrobić

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

zresetować SCOPE_IDENTITY() przed wykonaniem swojej drugi INSERT.

0

Po rozważeniu kilku alternatyw, ja znajduję się lubić riff na @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 

Jak widać z mojego ostatniego SELECT CASE..., w mojej sytuacji starałem się skończyć z jednym INT NOT NULL że pomogłoby rozumiem, czy wstawiono wiersz (w tym przypadku chciałem jego identyfikator), czy nie. (Nie polecam bycia w tej sytuacji, jeśli to możliwe!) To, co zrobiłbyś z @result, zależy od tego, co musisz zrobić.

Podoba mi się, że związek między INSERT i @result jest wyraźny i mało prawdopodobne, aby został skażony przez inne interweniujące operacje, o których mógłbym nie myśleć. Podoba mi się również to, że @result naturalnie obsługuje przypadki z więcej niż jednym wierszem.

Powiązane problemy