SQL Server - INSERT sonrası dönüş değeri


318

Bir INSERT deyimi sonra bir anahtar / değer elde etmeye çalışıyorum. Örnek: Ad ve kimliğe sahip bir tablo var. id, üretilen bir değerdir.

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

Şimdi aynı adımda kimliği geri almak istiyorum. Bu nasıl yapılır?

Microsoft SQL Server 2008 kullanıyoruz.


Burada yararlı bir cevap buldum: [deyim-dönüş-üretilen-anahtarları ile hazırlanma durumu] [1] [1]: stackoverflow.com/questions/4224228/…
Lars Ladegaard

Yanıtlar:


477

Ayrı bir SEÇİME gerek yok ...

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

Bu, IDENTITY olmayan sütunlar (GUID'ler gibi) için de geçerlidir


29
biraz ayrıntı verebilir misiniz? Çıktı bu örnekte nereye gidiyor? Dokümantasyon sadece tablolara ilişkin örnekleri gösterir (output ... into kullanılarak). İdeal olarak ben sadece bir değişkene geçmek mümkün olmak istiyorum
JonnyRaa

2
@JonnyLeeds: bunu bir değişkene yapamazsınız (tablo değişkeni olmadığı sürece). ÇIKTI istemciye veya masaya gidiyor
gbn

7
Maalesef, tabloya bir tetikleyici eklemek ifadelerinizi kıracağından buna güvenemezsiniz! re: blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/…
hajikelist

1
@hajikelist: Bu oldukça önemli bir durum, tetikte NCOOUNT AÇIK olarak ayarlamanız genellikle yardımcı olur. Bkz. Stackoverflow.com/questions/1483732/set-nocount-on-usage
gbn

5
Asla @@ IDENTITY kullanmayın. SCOPE_IDENTITY, evet, ama asla @@ IDENTITY. Güvenilmez
gbn

188

SCOPE_IDENTITY()Yeni kimlik değerini almak için kullanın

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

SELECT SCOPE_IDENTITY()

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


7
varsayarak idkimlik
Ilia G

12
@ liho1eye - OP, kimlik sütunu adına idevet denir .
Curt

3
Daha büyük sistemde, aynı anda çok sayıda sql çalıştırılırsa ne olur? Son eklenen kimliği her isteğe geri döndürecek mi?
Shiv

2
@Shiv "SCOPE_IDENTITY yalnızca geçerli kapsam içine eklenen değerleri döndürür"
goodies4uall 14:17

45
INSERT INTO files (title) VALUES ('whatever'); 
SELECT * FROM files WHERE id = SCOPE_IDENTITY();

Tetikleyicili tablolarda OUTPUT Clause çakışmasıyla ilgili bilinen bir sorun olduğundan en güvenli bahistir. Tablonuzun şu anda tetikleyicisi olmasa bile bunu oldukça güvenilir kılar - hatta bir satır ekleyen biri uygulamanızı kırar. Saatli Bomba bir tür davranış.

Daha ayrıntılı açıklama için msdn makalesine bakın:

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


Yalnızca tetikleyicilere SET NOCOUNT ON eklemezseniz. Ayrıca bkz. Docs.microsoft.com/en-us/sql/database-engine/configure-windows/…
gbn

Bu eski ortamlarımız için bir seçenek değil @gbn
hajikelist 16:18

@hajikelist Hepimiz mirasımız var, ancak ÇIKTI'yı karıştırmanın tetikleyici riski düşük, tek gereken açık değil. Birisi bir tetikleyici ekliyorsa, nasıl kodlayacağını bilmelidir (esas olarak kontrolünüz olduğunu ima eder) veya geliştiricilerinizi eğitmeniz gerekir .. Bir noktada, SQL'in bu sürümü artık olmadığında göç etmek zorunda kalacaksınız Tetikleyiciler bir sonuç kümesine neden olmaz. Her neyse, bu en iyi cevap değil çünkü INSTEAD OF tetikleyicileriniz varsa SCOPE_IDENTITY işe yaramayabilir ( stackoverflow.com/questions/908257/… )
gbn

@gbn - Böyle saçma şeylerden kaçınmayı seviyorum. Tüm geliştiricilerime "Her tetikleyicide" uygulama ifademi kırma "ifadesini eklemeyi unutmayın." - sende kalabilir. "Bunun yerine" senaryosu, daha çok bir uç durum imo'sudur.
hajikelist

Daha güvenli bir yanıt, uygulamanın bu sorgudan döndükten sonra başka bir sorgu çalıştırmasını sağlamak olabilir. Arka uçta yapıldığı sürece, performans cezası, insan gruplarındaki gelişimi yönetmenin basitliğine değer olmalı ve standartlara uygun olarak, kenar vakaları olan çılgın özelliklerden daha yakın. Kenar durumlarda kodumda olmayı ve platformlarda bunlardan kaçınmayı tercih ederim. sadece benim fikrim
Dan Chase

33

Entity Framework, gbn'nin cevabına benzer bir şey gerçekleştirir:

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

Çıktı sonuçları geçici bir tablo değişkeninde saklanır ve daha sonra istemciye geri seçilir. Gotcha farkında olmak zorunda:

ekler birden fazla satır oluşturabilir, bu nedenle değişken birden fazla satırı tutabilir, böylece birden fazla satır döndürülebilir ID

EF'in neden geçici masayı gerçek tabloya geri katacağı hakkında hiçbir fikrim yok (hangi koşullar altında ikisi eşleşmez).

Ama EF bunu yapar.

SQL Server 2008 veya daha yenisi. 2005 ise şanssızsınız demektir.


2
EF'nin bunu yapmasının nedeni, eklenen Customerkayıttaki diğer tüm değişiklikleri "görebildiğinden" emin olmaktır , çünkü onu etkileyen diğer DB tarafı mantığı olabilir, örneğin DEFAULTbazı sütunlarda, tablodaki tetikleyiciler vb. EF varlık (nesne) için kullanıldığından, istemci tarafı kimliğe ve satırın geçerli durumunu temsil eden diğer her şeye sahip müşteri nesnesini alır.
Hilarion

EF kullanmamanın bir başka nedeni.
cskwg

11

@@IDENTITY Son eklenen kimlik değerini döndüren bir sistem işlevidir.


4
@@ IDENTITY kullanarak hiç tavsiye etmemelisiniz - doğru (çok geniş) çok daha az güvenli değildir - lütfen @ Curt'in SCOPE_IDENTITY () hakkındaki cevabına bakın.
zanlok

10

Eklemeden sonra çıkmanın birçok yolu vardır

Bir tabloya veri eklediğinizde, tabloya eklenen verilerin bir kopyasını döndürmek için ÇIKTI yan tümcesini kullanabilirsiniz. OUTPUT deyimi iki temel biçim alır: OUTPUT ve OUTPUT INTO. Verileri çağıran uygulamaya döndürmek istiyorsanız ÇIKTI formunu kullanın. Verileri bir tabloya veya tablo değişkenine döndürmek istiyorsanız OUTPUT INTO formunu kullanın.

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

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

IDENT_CURRENT : Herhangi bir oturumda belirli bir tablo veya görünüm için oluşturulan son kimliği döndürür.

SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]

SCOPE_IDENTITY : Aynı oturumun ve aynı kapsamın son kimliğini döndürür. Kapsam, saklı bir yordam / tetikleyicidir vb.

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];  

@@ IDENTITY : Aynı oturumdaki son kimliği döndürür.

SELECT @@IDENTITY AS [@@IDENTITY];

1
@RezaJenabi Haziran, dışarı koymak çok iyi çalıştı, tablodaki birçok kimliği bulmak daha iyidir. Kullandığım out putiçin bulk insertve ekine select statement. öneri teşekkürler
Amirhossein

5

En iyi ve en kesin çözüm kullanmaktır SCOPE_IDENTITY().

Her eklemeden sonra kapsam kimliğini almanız ve bir değişkene kaydetmeniz gerekir, çünkü aynı kapsamda iki eklenti çağırabilirsiniz.

ident_currentve çalışıyor @@identityolabilirler ama güvenli kapsam değildirler. Büyük bir uygulamada sorun yaşayabilirsiniz

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

Daha fazla ayrıntı burada Microsoft belgeleri


1
Bunu basitleştirebilirselect @duplicataId = SCOPE_IDENTITY()
13'te pcnate

1
OUTPUTfıkra daha iyi, daha saf bir çözümdür :)
Dale K

OUTPUT INTO çok yavaş.
cskwg


1

Insert komutundan sonra en son eklenen kimliği almanın birden çok yolu vardır.

  1. @@IDENTITY : Tablo ve değeri üreten ifadenin kapsamından bağımsız olarak, geçerli oturumda bir Bağlantıda oluşturulan son Kimlik değerini döndürür
  2. SCOPE_IDENTITY(): Tablodan bağımsız olarak geçerli bağlantıda geçerli kapsamda insert deyimi tarafından üretilen son kimlik değerini döndürür.
  3. IDENT_CURRENT(‘TABLENAME’): Herhangi bir bağlantı, oturum veya kapsamdan bağımsız olarak belirtilen tabloda oluşturulan son kimlik değerini döndürür. IDENT_CURRENT, kapsam ve oturumla sınırlı değildir; belirtilen bir tabloyla sınırlıdır.

Şimdi hangisinin ihtiyacım için tam olarak eşleşeceğine karar vermek daha zor görünüyor.

Çoğunlukla SCOPE_IDENTITY () yöntemini tercih ederim.

Insert deyiminde TableName ile birlikte select SCOPE_IDENTITY () yöntemini kullanırsanız, beklentinize göre kesin sonuç elde edersiniz.

Kaynak: CodoBee


0

SQL Server'da kimlik sütunu olarak kimlik kullanan bir tabloya eklerken, OUTPUT INSERTED'i şu şekilde kullanıyorum:

'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)

0

Insert deyiminize bir select deyimi ekleyebilirsiniz. Integer myInt = table1 (FName) değerlerine ekle ('Fred'); Scope_Identity () öğesini seçin; Bu, ölçekleyici yürütüldüğünde kimliğin bir değerini döndürür.



-4

* Bağlantı dizesindeki parametre sırası bazen önemlidir. * Sağlayıcı parametresinin konumu, bir satır ekledikten sonra kayıt kümesi imlecini kırabilir. Bu davranışı SQLOLEDB sağlayıcısı ile gördük.

Bir satır eklendikten sonra, satır alanları kullanılamaz, Sağlayıcının bağlantı dizesindeki ilk parametre OLMADIĞINI belirtir . Sağlayıcı, bağlantı parametresinde ilk parametre dışında herhangi bir yerde olduğunda, yeni eklenen satır alanları kullanılamaz. Sağlayıcıyı ilk parametreye taşıdığımızda, satır alanları sihirli bir şekilde ortaya çıktı.


1
Bu yorumun, sorulan soruya nasıl cevap verdiğini / ilgili olduğunu söyleyebilir misiniz? Kapakları / cesurluğu hak ettiğini düşünmüyorum. Cevabınız faydalı sayılırsa, kullanıcılar oy verecektir.
n__o

Çok sayıda kullanıcı muhtemelen bu sayfaya geldi, çünkü yeni eklenen satırı tanımlamak için geçerli alanları yoktu. Bulduğumuz bu davranış (sadece bağlantı dizesindeki parametrelerin sırasını değiştirmenin yeni eklenen satıra hemen erişmesine izin vermesi) o kadar tuhaf ki, kapaklarda belirtmeyi hak ettiğini düşündüm, özellikle de insanların yeni satır kimliği ve bu satırın diğer alanları. Sağlayıcıyı ilk parametre olarak koyarak sorun ortadan kalkar.
David Guidos

Cevabınızı düzenlemeniz ve geliştirmeniz gerekiyor. Şu anda gürültülü ve iyi bir cevap ya da bir girişim olarak karşımıza çıkmıyor
James

"Gürültülü" ile tam olarak ne demek istiyorsun? Şikayetinizi açıklamanız gerekiyor. Olabildiğince basit. Bağlantı dizenizdeki parametrelerin sırasını değiştirirseniz, eklemeden sonra satır verilerinin kullanılabilir olup olmayacağı etkilenebilir.
David Guidos
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.