Máy chủ SQL - Trả về giá trị sau INSERT


318

Tôi đang cố gắng lấy lại giá trị khóa sau câu lệnh INSERT. Ví dụ: Tôi đã có một bảng có tên thuộc tính và id. id là một giá trị được tạo ra.

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

Bây giờ tôi muốn lấy lại id trong cùng một bước. Làm thế nào được thực hiện?

Chúng tôi đang sử dụng Microsoft SQL Server 2008.


Tôi đã tìm thấy một câu trả lời hữu ích ở đây: [yetstatement-with-statement-return-created-key] [1] [1]: stackoverflow.com/questions/4224228/
Lars Ladegaard 15/10/13

Câu trả lời:


477

Không cần CHỌN riêng ...

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

Điều này cũng hoạt động cho các cột không IDENTITY (chẳng hạn như GUID)


29
bạn có thể xây dựng một chút? Trường hợp đầu ra đi trong ví dụ này? Tài liệu này chỉ hiển thị các ví dụ cho các bảng (sử dụng đầu ra ... vào). Lý tưởng nhất là tôi muốn có thể chuyển nó thành một biến
JonnyRaa

2
@JonnyLeed: bạn không thể làm điều đó với một biến (trừ khi một biến bảng). OUTPUT đi đến máy khách hoặc bảng
gbn

7
Thật không may, bạn không thể dựa vào điều này vì việc thêm một kích hoạt vào bảng sẽ phá vỡ các tuyên bố của bạn! re: blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/...
hajikelist

1
@hajikelist: đây là một trường hợp khá, cài đặt NCOOUNT ON trong trình kích hoạt thường giúp. Xem stackoverflow.com/questions/1483732/set-nocount-on-usage
gbn

5
Không bao giờ sử dụng @@ IDENTITY. SCOPE_IDENTITY, có, nhưng không bao giờ @@ IDENTITY. Nó không đáng tin cậy
gbn

188

Sử dụng SCOPE_IDENTITY()để nhận giá trị ID mới

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

SELECT SCOPE_IDENTITY()

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


7
giả sử idlà danh tính
Ilia G

12
@ liho1eye - OP gọi tên cột nhận dạng là id, nên có.
Curt

3
Trên hệ thống lớn hơn, điều gì sẽ xảy ra nếu nhiều sql chạy cùng một lúc? Nó sẽ trả lại id được chèn cuối cùng cho mọi yêu cầu?
Shiv

2
@Shiv "SCOPE_IDENTITY chỉ trả về các giá trị được chèn trong phạm vi hiện tại"
goodies4uall

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

Là cược an toàn nhất vì có một vấn đề đã biết với xung đột Khoản OUTPUT trên các bảng có kích hoạt. Làm cho điều này khá không đáng tin vì ngay cả khi bảng của bạn hiện không có bất kỳ trình kích hoạt nào - ai đó thêm một dòng xuống sẽ phá vỡ ứng dụng của bạn. Bom hẹn giờ sắp xếp hành vi.

Xem bài viết msDN để được giải thích sâu hơn:

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


Chỉ khi bạn không thêm SET NOCOUNT ON trong trình kích hoạt. Ngoài ra, hãy xem docs.microsoft.com/en-us/sql/database-engine/configure-windows/ mẹo
gbn

đây không phải là một lựa chọn cho môi trường kế thừa của chúng tôi @gbn
hajikelist 16/03/18

@hajikelist Tất cả chúng ta đều có di sản, nhưng nguy cơ kích hoạt OUTPUT gây rối là rất thấp, tất cả những gì nó cần được đặt là không cần thiết. Nếu ai đó đang thêm trình kích hoạt thì họ nên biết cách mã hóa nó (ngụ ý bạn chủ yếu kiểm soát) hoặc bạn cần đào tạo các nhà phát triển của mình .. Đến một lúc nào đó, bạn sẽ buộc phải di chuyển khi phiên bản SQL đó không còn được hỗ trợ, vì vậy các trình kích hoạt sẽ không gây ra kết quả. Dù thế nào đi nữa, đó không phải là câu trả lời tốt nhất bởi vì nếu bạn đã kích hoạt INSTEAD OF thì SCOPE_IDENTITY có thể không hoạt động ( stackoverflow.com/questions/908257/ Lỗi )
gbn

@gbn - Tôi chỉ muốn tránh những thứ ngớ ngẩn như thế này. Tôi sẽ không nói với tất cả các nhà phát triển của mình, "Đừng quên thêm 'không phá vỡ tuyên bố ứng dụng của tôi' trong mỗi kích hoạt." - bạn có thể giữ nó. Kịch bản "thay thế" là nhiều hơn một trường hợp cạnh imo.
hajikelist 16/03/18

Một câu trả lời an toàn hơn có thể chỉ là để ứng dụng chạy một truy vấn khác một khi nó trả về từ câu hỏi này. Miễn là nó được thực hiện ở mặt sau, hình phạt về hiệu suất nên có giá trị đơn giản trong việc quản lý sự phát triển trong các nhóm người và nó gần với các tiêu chuẩn hơn so với một số tính năng điên rồ với các trường hợp cạnh. Tôi muốn thay vào đó là các trường hợp cạnh nằm trong mã của tôi và tránh chúng trên các nền tảng. chỉ là ý kiến ​​của tôi không có gì lạ lùng :)
Dan Chase

33

Entity Framework thực hiện một cái gì đó tương tự như câu trả lời của 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

Các kết quả đầu ra được lưu trữ trong một biến bảng tạm thời, và sau đó được chọn trở lại máy khách. Phải có ý thức về gotcha:

các phần chèn có thể tạo nhiều hơn một hàng, vì vậy biến có thể chứa nhiều hơn một hàng, do đó bạn có thể được trả về nhiều hơn một hàng ID

Tôi không biết tại sao EF lại tham gia vào bảng phù du trở lại bàn thực (trong trường hợp nào hai người sẽ không khớp nhau).

Nhưng đó là những gì EF làm.

SQL Server 2008 hoặc mới hơn. Nếu đó là năm 2005 thì bạn đã hết may mắn.


2
Lý do mà EF thực hiện là để đảm bảo rằng nó cũng có thể "nhìn thấy" tất cả các thay đổi khác đối với Customerbản ghi được chèn , vì có thể có logic bên DB khác ảnh hưởng đến nó, ví dụ như DEFAULTtrên một số cột, kích hoạt trên bảng, v.v. thực thể (đối tượng) nó được sử dụng để chèn, vì vậy phía khách hàng có được đối tượng khách hàng với ID và mọi thứ khác thể hiện trạng thái hiện tại của hàng.
Hilarion

Một lý do khác để không sử dụng EF.
cskwg

11

@@IDENTITY Là một hàm hệ thống trả về giá trị nhận dạng được chèn cuối cùng.


4
Phải khuyên bạn không bao giờ sử dụng @@ IDENTITY - nó không chính xác (quá rộng) ít an toàn cho chủ đề hơn - vui lòng xem câu trả lời của @ Curt về SCOPE_IDENTITY ().
zanlok

10

Có nhiều cách để thoát sau khi chèn

Khi bạn chèn dữ liệu vào một bảng, bạn có thể sử dụng mệnh đề OUTPUT để trả về một bản sao của dữ liệu được chèn vào bảng. Mệnh đề OUTPUT có hai dạng cơ bản: OUTPUT và OUTPUT INTO. Sử dụng biểu mẫu OUTPUT nếu bạn muốn trả lại dữ liệu cho ứng dụng gọi điện. Sử dụng biểu mẫu OUTPUT INTO nếu bạn muốn trả lại dữ liệu cho một bảng hoặc một biến bảng.

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

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

IDENT_CURRENT : Nó trả về danh tính cuối cùng được tạo cho một bảng hoặc chế độ xem cụ thể trong bất kỳ phiên nào.

SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]

SCOPE_IDENTITY : Nó trả về danh tính cuối cùng từ cùng một phiên và cùng phạm vi. Một phạm vi là một thủ tục lưu trữ / kích hoạt, vv

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];  

@@ IDENTITY : Nó trả về danh tính cuối cùng từ cùng một phiên.

SELECT @@IDENTITY AS [@@IDENTITY];

1
@RezaJenabi Jun, out put hoạt động rất tốt, tốt hơn là tìm nhiều id trong bảng. Tôi đã từng out putcho bulk insertvà chèn bằng select statement. cảm ơn đề nghị của bạn
Amirhossein

5

Giải pháp tốt nhất và chắc chắn nhất là sử dụng SCOPE_IDENTITY().

Chỉ cần bạn phải có được danh tính phạm vi sau mỗi lần chèn và lưu nó vào một biến vì bạn có thể gọi hai lần chèn trong cùng một phạm vi.

ident_current@@identitycó thể chúng hoạt động nhưng chúng không phải là phạm vi an toàn. Bạn có thể có vấn đề trong một ứng dụng lớn

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

Chi tiết hơn là ở đây tài liệu Microsoft


1
Có thể đơn giản hóa việc này thànhselect @duplicataId = SCOPE_IDENTITY()
pcnate

1
OUTPUTmệnh đề là một giải pháp tốt hơn, thuần túy hơn :)
Dale K

ĐẦU RA VÀO rất chậm.
cskwg

4

Bạn có thể sử dụng scope_identity()để chọn ID của hàng bạn vừa chèn vào một biến sau đó chỉ cần chọn bất kỳ cột nào bạn muốn từ bảng đó có id = danh tính bạn nhận được từscope_identity()

Xem tại đây để biết thông tin MSDN http://msdn.microsoft.com/en-us/l Library / ms190315.aspx


1

Có nhiều cách để lấy ID được chèn cuối cùng sau lệnh chèn.

  1. @@IDENTITY : Nó trả về giá trị Danh tính cuối cùng được tạo trên Kết nối trong phiên hiện tại, bất kể Bảng và phạm vi của câu lệnh đã tạo ra giá trị
  2. SCOPE_IDENTITY(): Nó trả về giá trị nhận dạng cuối cùng được tạo bởi câu lệnh chèn trong phạm vi hiện tại trong kết nối hiện tại bất kể bảng.
  3. IDENT_CURRENT(‘TABLENAME’): Nó trả về giá trị nhận dạng cuối cùng được tạo trên bảng đã chỉ định bất kể kết nối, phiên hoặc phạm vi. IDENT_CURRENT không bị giới hạn bởi phạm vi và phiên; nó được giới hạn trong một bảng được chỉ định.

Bây giờ có vẻ khó khăn hơn để quyết định cái nào sẽ phù hợp chính xác cho yêu cầu của tôi.

Tôi chủ yếu thích SCOPE_IDENTITY ().

Nếu bạn sử dụng chọn SCOPE_IDENTITY () cùng với TableName trong câu lệnh chèn, bạn sẽ nhận được kết quả chính xác theo mong đợi của mình.

Nguồn: CodoBee


0

Đây là cách tôi sử dụng OUTPUT INSERTED, khi chèn vào bảng sử dụng ID làm cột nhận dạng trong 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)

0

Bạn có thể nối một câu lệnh chọn vào câu lệnh chèn của bạn. Số nguyên myInt = Chèn vào giá trị bảng1 (FName) ('Fred'); Chọn Phạm vi_Identity (); Điều này sẽ trả về một giá trị của danh tính khi thực hiện scaler.


-4

Sau khi thực hiện thao tác chèn vào bảng có cột nhận dạng, bạn có thể tham khảo @@ IDENTITY để nhận giá trị: http://msdn.microsoft.com/en-us/l Library / aa933167% 28v = sql.80% 29.aspx


24
Không bao giờ sử dụng @@ IDENTITY: nó không phạm vi an toàn: kích hoạt, vv ảnh hưởng đến nó.
gbn

-4

* Thứ tự tham số trong chuỗi kết nối đôi khi rất quan trọng. * Vị trí của tham số Nhà cung cấp có thể phá vỡ con trỏ recordset sau khi thêm một hàng. Chúng tôi đã thấy hành vi này với nhà cung cấp SQLOLEDB.

Sau khi một hàng được thêm vào, các trường hàng không có sẵn, KHÔNG GIỚI HẠN Nhà cung cấp được chỉ định làm tham số đầu tiên trong chuỗi kết nối. Khi nhà cung cấp ở bất kỳ đâu trong chuỗi kết nối ngoại trừ tham số đầu tiên, các trường hàng mới được chèn sẽ không khả dụng. Khi chúng tôi di chuyển Nhà cung cấp đến tham số đầu tiên, các trường hàng xuất hiện một cách kỳ diệu.


1
Bạn có thể cho chúng tôi biết câu trả lời nhận xét này / có liên quan đến câu hỏi đã được hỏi không? Tôi không cảm thấy nó xứng đáng mũ / đậm. Nếu câu trả lời của bạn được coi là hữu ích, người dùng sẽ bỏ phiếu.
n__o

Rất nhiều người dùng có thể đã truy cập trang này vì họ không có các trường hợp lệ để xác định hàng vừa thêm. Hành vi này chúng tôi đã tìm thấy (chỉ cần thay đổi thứ tự các tham số trong chuỗi kết nối cho phép truy cập vào hàng mới được thêm ngay lập tức) rất kỳ lạ đến nỗi tôi nghĩ rằng nó đáng được đề cập trong mũ, đặc biệt là vì nó rất có thể sẽ khắc phục lý do mọi người muốn cái mới ID hàng và các trường khác của hàng đó. Chỉ cần đặt nhà cung cấp làm tham số đầu tiên, vấn đề sẽ biến mất.
David Guidos

Bạn cần chỉnh sửa và cải thiện câu trả lời của bạn. Nó hiện đang ồn ào và không đi qua như một câu trả lời đàng hoàng hay thậm chí là một nỗ lực
James

Chính xác thì bạn có ý gì khi "ồn ào"? Bạn cần giải thích khiếu nại của bạn. Nó đơn giản như nó có thể được. Nếu bạn thay đổi thứ tự của các tham số trong chuỗi kết nối của mình, điều đó có thể ảnh hưởng đến việc liệu dữ liệu hàng có khả dụng sau khi chèn hay không.
David Guidos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.