SQL Server - Zwraca wartość po INSERT

318

Próbuję odzyskać klucz-wartość z powrotem po instrukcji INSERT. Przykład: Mam tabelę z nazwą atrybutu i identyfikatorem. id to wygenerowana wartość.

    INSERT INTO table (name) VALUES('bob');

Teraz chcę odzyskać identyfikator w tym samym kroku. Jak to się robi?

Używamy Microsoft SQL Server 2008.

melbiczny
źródło
Znalazłem użyteczną odpowiedź tutaj: [przygotowanystatement-z-instrukcją-wygenerowanymi-kluczami] [1] [1]: stackoverflow.com/questions/4224228/...
Lars Ladegaard

Odpowiedzi:

477

Nie ma potrzeby oddzielnego WYBIERZ ...

INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');

Działa to również w przypadku kolumn bez tożsamości (takich jak GUID)

gbn
źródło
29
mógłbyś trochę rozwinąć? Gdzie idzie wyjście w tym przykładzie? Dokumentacja pokazuje tylko przykłady tabel (przy użyciu danych wyjściowych ... do). Idealnie chciałbym móc po prostu przekazać ją do zmiennej
JonnyRaa
2
@JonnyLeeds: nie można tego zrobić ze zmienną (chyba że zmienna tabelowa). WYJŚCIE trafia do klienta lub stołu
2014 r. O
7
Niestety nie możesz na tym polegać, ponieważ dodanie wyzwalacza do tabeli spowoduje uszkodzenie instrukcji! re: blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/…
hajikelist
1
@hajikelist: jest to dość ostry przypadek, zwykle pomaga ustawić NCOOUNT w wyzwalaczu. Zobacz stackoverflow.com/questions/1483732/set-nocount-on-usage
gbn
5
Nigdy nie używaj @@ TOŻSAMOŚCI. SCOPE_IDENTITY, tak, ale nigdy @@ TOŻSAMOŚĆ. To niewiarygodne
2017
188

Użyj, SCOPE_IDENTITY()aby uzyskać nową wartość identyfikatora

INSERT INTO table (name) VALUES('bob');

SELECT SCOPE_IDENTITY()

http://msdn.microsoft.com/en-us/library/ms190315.aspx

Lakoniczny
źródło
7
zakładając, że idto tożsamość
Ilia G
12
@ liho1eye - OP odniósł się do nazwy kolumny tożsamości jako id, więc tak.
Curt
3
W większym systemie, co jeśli wiele sqlów działa w tym samym czasie? Czy zwróci ostatni wstawiony identyfikator do każdego żądania?
Shiv,
2
@Shiv „SCOPE_IDENTITY zwraca wartości wstawione tylko w bieżącym zakresie”
goodies4uall,
45
INSERT INTO files (title) VALUES ('whatever'); 
SELECT * FROM files WHERE id = SCOPE_IDENTITY();

Jest najbezpieczniejszym zakładem, ponieważ istnieje znany problem z konfliktem klauzul OUTPUT w tabelach z wyzwalaczami. Sprawia, że ​​jest to dość niewiarygodne, ponieważ nawet jeśli twoja tabela nie ma obecnie żadnych wyzwalaczy - ktoś dodając jeden w dół linii złamie twoją aplikację. Zachowanie związane z bombą zegarową.

Bardziej szczegółowe wyjaśnienia znajdują się w artykule msdn:

http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx

lista pielęgniarek
źródło
Tylko jeśli nie dodasz SET NOCOUNT ON w wyzwalaczach. Zobacz także docs.microsoft.com/en-us/sql/database-engine/configure-windows/…
gbn
nie jest to opcja dla naszych starszych środowisk @gbn
hajikelist
@hajikelist Wszyscy mamy spuściznę, ale ryzyko wywołania bałaganu w WYJŚCIACH jest niskie, wystarczy tylko włączyć opcję nocount. Jeśli ktoś dodaje wyzwalacz, powinien wiedzieć, jak go kodować (co oznacza, że ​​masz kontrolę głównie), lub musisz przeszkolić programistów. W pewnym momencie będziesz zmuszony do migracji, gdy ta wersja SQL nie będzie już obsługiwane itp., więc wyzwalacze nie spowodują zestawu wyników. Cokolwiek, nie jest to najlepsza odpowiedź, ponieważ jeśli masz INSTEAD OF wyzwalaczy, SCOPE_IDENTITY może nie działać ( stackoverflow.com/questions/908257/… )
gbn
@ gbn - Po prostu lubię unikać takich głupich rzeczy jak ta. Nie powiem wszystkim moim programistom: „Nie zapomnij dodać słowa„ nie łam mojej instrukcji aplikacji ”przy każdym wyzwalaczu”. - możesz to zatrzymać. Scenariusz „zamiast” jest znacznie bardziej imo.
hajikelist
Bezpieczniejszą odpowiedzią może być uruchomienie przez aplikację kolejnej kwerendy po jej zwróceniu. Tak długo, jak dzieje się to na zapleczu, kara za wydajność powinna być warta prostoty zarządzania rozwojem w grupach ludzi i jest bliższa standardom niż jakaś szalona cecha z przypadkowymi przypadkami. Wolałbym, aby przypadki brzegowe były w moim kodzie i unikałem ich na platformach. tylko moja opinia nie wariuje :)
Dan Chase
33

Entity Framework wykonuje coś podobnego do odpowiedzi gbn:

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO Customers(FirstName)
OUTPUT inserted.CustomerID INTO @generated_keys
VALUES('bob');

SELECT t.[CustomerID]
FROM @generated_keys AS g 
   JOIN dbo.Customers AS t 
   ON g.Id = t.CustomerID
WHERE @@ROWCOUNT > 0

Wyniki wyjściowe są przechowywane w tymczasowej zmiennej tabeli, a następnie wybierane z powrotem do klienta. Musisz być świadomy gotcha:

wstawki mogą generować więcej niż jeden wiersz, więc zmienna może pomieścić więcej niż jeden wiersz, dzięki czemu można zwrócić więcej niż jeden wiersz ID

Nie mam pojęcia, dlaczego EF połączyłby efemeryczny stół z powrotem z prawdziwym stołem (w jakich okolicznościach te dwa nie pasowałyby).

Ale tak właśnie działa EF.

SQL Server 2008 lub nowszy. Jeśli jest 2005, to nie masz szczęścia.

Ian Boyd
źródło
2
EF robi to, aby upewnić się, że może również „zobaczyć” wszystkie inne zmiany we wstawionym Customerrekordzie, ponieważ mogą mieć na to wpływ inne logiki po stronie DB, np. W DEFAULTniektórych kolumnach, wyzwalacze w tabeli itp. EF aktualizuje encja (obiekt) użyta do wstawiania, więc strona klienta otrzymuje obiekt klienta z identyfikatorem i wszystkim innym, reprezentującym bieżący stan wiersza.
Hilarion
Kolejny powód, aby nie używać EF.
cskwg
11

@@IDENTITY Jest funkcją systemową, która zwraca ostatnio wstawioną wartość tożsamości.

AngelaG
źródło
4
Odradzam używanie @@ TOŻSAMOŚCI - nie jest dokładne (zbyt szerokie), a tym samym mniej bezpieczne dla wątków - zobacz odpowiedź @ Curt'a na temat SCOPE_IDENTITY ().
zanlok 16.04.18
10

Istnieje wiele sposobów wyjścia po wstawieniu

Podczas wstawiania danych do tabeli można użyć klauzuli OUTPUT, aby zwrócić kopię danych wstawionych do tabeli. Klauzula OUTPUT przybiera dwie podstawowe formy: OUTPUT i OUTPUT INTO. Użyj formularza WYJŚCIE, jeśli chcesz zwrócić dane do aplikacji wywołującej. Użyj formularza WYJŚCIE DO, jeśli chcesz zwrócić dane do tabeli lub zmiennej tabeli.

DECLARE @MyTableVar TABLE (id INT,NAME NVARCHAR(50));

INSERT INTO tableName
(
  NAME,....
)OUTPUT INSERTED.id,INSERTED.Name INTO @MyTableVar
VALUES
(
   'test',...
)

IDENT_CURRENT : Zwraca ostatnią tożsamość utworzoną dla określonej tabeli lub widoku w dowolnej sesji.

SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]

SCOPE_IDENTITY : Zwraca ostatnią tożsamość z tej samej sesji i tego samego zakresu. Zakres jest procedurą przechowywaną / wyzwalaczem itp.

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];  

@@ TOŻSAMOŚĆ : Zwraca ostatnią tożsamość z tej samej sesji.

SELECT @@IDENTITY AS [@@IDENTITY];
Reza Jenabi
źródło
1
@RezaJenabi Jun, out put jest bardzo dobrze przepracowany, jest lepszy niż znaleźć wiele identyfikatorów w tabeli. Kiedyś out putdla bulk inserti przez wkładkę select statement. dziękuję za twoją sugestię
Amirhossein
5

Używa najlepszego i najbardziej pewnego rozwiązania SCOPE_IDENTITY().

Trzeba tylko uzyskać tożsamość zasięgu po każdej wstawce i zapisać ją w zmiennej, ponieważ można wywołać dwie wstawki w tym samym zakresie.

ident_currenti @@identitybyć może działają, ale nie są bezpiecznym zakresem. Możesz mieć problemy w dużej aplikacji

  declare @duplicataId int
  select @duplicataId =   (SELECT SCOPE_IDENTITY())

Więcej szczegółów znajduje się tutaj Dokumenty Microsoft

MNF
źródło
1
Można to uprościć doselect @duplicataId = SCOPE_IDENTITY()
pcnate
1
OUTPUTklauzula jest lepszym, czystszym rozwiązaniem :)
Dale K
WYJŚCIE DO jest bardzo wolne.
cskwg
4

Możesz użyć, scope_identity()aby wybrać identyfikator wiersza, który właśnie wstawiłeś do zmiennej, a następnie wybierz dowolne kolumny z tabeli, w której id = tożsamość, którą otrzymałeśscope_identity()

Zobacz tutaj informacje MSDN http://msdn.microsoft.com/en-us/library/ms190315.aspx

Purplegoldfish
źródło
1

Istnieje wiele sposobów uzyskania ostatniego wstawionego identyfikatora po poleceniu wstawiania.

  1. @@IDENTITY : Zwraca ostatnią wartość tożsamości wygenerowaną dla połączenia w bieżącej sesji, niezależnie od tabeli i zakresu instrukcji, która wygenerowała tę wartość
  2. SCOPE_IDENTITY(): Zwraca ostatnią wartość tożsamości wygenerowaną przez instrukcję insert w bieżącym zakresie w bieżącym połączeniu, niezależnie od tabeli.
  3. IDENT_CURRENT(‘TABLENAME’): Zwraca ostatnią wartość tożsamości wygenerowaną w określonej tabeli, niezależnie od Dowolnego połączenia, sesji lub zakresu. IDENT_CURRENT nie jest ograniczony zakresem i sesją; jest ograniczony do określonej tabeli.

Teraz trudniej jest zdecydować, który z nich będzie dokładnie pasował do moich wymagań.

Najbardziej preferuję SCOPE_IDENTITY ().

Jeśli użyjesz select SCOPE_IDENTITY () wraz z TableName w instrukcji insert, otrzymasz dokładny wynik zgodnie z twoimi oczekiwaniami.

Źródło: CodoBee

Ishrar
źródło
0

Oto jak używam OUTPUT INSERTED podczas wstawiania do tabeli, która używa ID jako kolumny tożsamości w SQL Server:

'myConn is the ADO connection, RS a recordset and ID an integer
Set RS=myConn.Execute("INSERT INTO M2_VOTELIST(PRODUCER_ID,TITLE,TIMEU) OUTPUT INSERTED.ID VALUES ('Gator','Test',GETDATE())")
ID=RS(0)
Richard Zembron
źródło
0

Możesz dołączyć instrukcję select do instrukcji insert. Liczba całkowita myInt = Wstaw do wartości table1 (FName) („Fred”); Wybierz Scope_Identity (); Zwróci to wartość tożsamości podczas wykonywania skalera.

Robert Quinn
źródło
-4

* Kolejność parametrów w ciągu połączenia jest czasem ważna. * Lokalizacja parametru dostawcy może złamać kursor zestawu rekordów po dodaniu wiersza. Widzieliśmy to zachowanie u dostawcy SQLOLEDB.

Po dodaniu wiersza pola wiersza nie są dostępne, chyba że dostawca jest określony jako pierwszy parametr w ciągu połączenia. Gdy dostawca jest gdziekolwiek w ciągu połączenia, z wyjątkiem pierwszego parametru, nowo wstawione pola wiersza są niedostępne. Kiedy przenieśliśmy Dostawcę do pierwszego parametru, pola wierszy magicznie się pojawiły.

David Guidos
źródło
1
Czy możesz nam powiedzieć, w jaki sposób ten komentarz odpowiada / odnosi się do zadanego pytania? Nie sądzę, że zasługuje na czapki / pogrubienie. Jeśli twoja odpowiedź zostanie uznana za pomocną, użytkownicy głosują na nią.
n__o
Prawdopodobnie wielu użytkowników przyszło na tę stronę, ponieważ nie mieli prawidłowych pól identyfikujących właśnie dodany wiersz. Znalezione przez nas zachowanie (że po prostu zmiana kolejności parametrów w ciągu połączenia umożliwia natychmiastowy dostęp do nowo dodanego wiersza) jest tak dziwne, że myślałem, że zasługuje na wzmiankę o wielkich literach, zwłaszcza że prawdopodobnie naprawi to powód, dla którego ludzie chcą nowego identyfikator wiersza i inne pola tego wiersza. Po prostu umieszczając dostawcę jako pierwszy parametr, problem znika.
David Guidos,
Musisz edytować i poprawić swoją odpowiedź. Obecnie jest głośno i nie wydaje się przyzwoitą odpowiedzią ani nawet próbą
James
Co dokładnie rozumiesz przez „głośny”? Musisz wyjaśnić swoją skargę. To jest tak proste, jak to tylko możliwe. Zmiana kolejności parametrów w ciągu połączenia może mieć wpływ na to, czy dane wiersza są dostępne po wstawieniu.
David Guidos,