SQL: Làm cách nào để lấy id của các giá trị tôi vừa CHÈN?


76

Tôi đã chèn một số giá trị vào một bảng. Có một cột có giá trị được tạo tự động. Trong câu lệnh tiếp theo của mã của tôi, tôi muốn truy xuất giá trị này.

Bạn có thể cho tôi biết làm thế nào để làm điều đó một cách đúng đắn?


6
Sẽ hữu ích nếu bạn cung cấp một số chi tiết về cơ sở dữ liệu bạn đang sử dụng vì các kỹ thuật khác nhau.
Dhaust

Câu trả lời:


57

@@IDENTITY không an toàn trong phạm vi và sẽ giúp bạn lấy lại id từ bảng khác nếu bạn có trình kích hoạt chèn trên bảng gốc, hãy luôn sử dụng SCOPE_IDENTITY()


2
có lỗi đã biết với SCOPE_IDENTITY () trong máy chủ sql 2005, không chắc chắn về năm 2008, mệnh đề OUTPUT có thể trả về một bộ ID nếu cần
KM.

1
lỗi đã biết với SCOPE_IDENTITY () trả về các giá trị sai: blog.sqlauthority.com/2009/03/24/… công việc xung quanh là không chạy INSERT trong Gói song song nhiều bộ xử lý hoặc sử dụng mệnh đề OUTPUT
KM.

4
URL bị cắt trên nhận xét bởi @KM. vì vậy hy vọng liên kết này hoạt động: SCOPE_IDENTITY Bug với Multi Processor Song song Kế hoạch và Giải pháp
James Skemp

29

Đây là cách tôi thực hiện các thủ tục lưu trữ của mình cho MSSQL với ID được tạo tự động.

CREATE PROCEDURE [dbo].[InsertProducts]
    @id             INT             = NULL OUT,
    @name           VARCHAR(150)    = NULL,
    @desc           VARCHAR(250)    = NULL

AS

    INSERT INTO dbo.Products
       (Name,
        Description)
    VALUES
       (@name,
        @desc)

    SET @id = SCOPE_IDENTITY();

14

Nếu bạn sử dụng PHP và MySQL, bạn có thể sử dụng hàm mysql_insert_id () sẽ cho bạn biết ID của mục bạn vừa chèn.
Nhưng không có Ngôn ngữ và DBMS của bạn, tôi chỉ chụp trong bóng tối ở đây.


14

Điều này hoạt động rất tốt trong SQL 2005:

DECLARE @inserted_ids TABLE ([id] INT);

INSERT INTO [dbo].[some_table] ([col1],[col2],[col3],[col4],[col5],[col6])
OUTPUT INSERTED.[id] INTO @inserted_ids
VALUES (@col1,@col2,@col3,@col4,@col5,@col6)

Nó có lợi ích là trả về tất cả các ID nếu câu lệnh INSERT của bạn chèn nhiều hàng.


11

Một lần nữa không có phản hồi bất khả tri ngôn ngữ, nhưng trong Java nó diễn ra như thế này:

Connection conn = Database.getCurrent().getConnection();  
PreparedStatement ps =  conn.prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS);
try {  
    ps.executeUpdate();  
    ResultSet rs = ps.getGeneratedKeys();  
    rs.next();  
    long primaryKey = rs.getLong(1);  
} finally {  
    ps.close();  
}  

Thật tuyệt, tôi chỉ đang tìm kiếm cái này
raupach

8

Nếu bạn đang làm việc với Oracle:

Chèn vào bảng (Trường ...) giá trị (Giá trị ...) QUAY LẠI (Danh sách trường ...) INTO (biến ...)

thí dụ:

CHÈN VÀO GIÁ TRỊ CỦA NGƯỜI (TÊN) ('JACK') QUAY LẠI ID_PERSON VÀO vIdPerson

hoặc nếu bạn đang gọi từ ... Java với CallableStatement (sry, đó là trường của tôi)

CHÈN VÀO GIÁ TRỊ CỦA NGƯỜI (TÊN) ('JACK') QUAY LẠI ID_PERSON VÀO?

và khai báo một tham số tự động nhập cho câu lệnh


6

Không có cách chuẩn nào để làm điều đó (cũng như không có cách chuẩn nào để tạo ID tự động tăng dần). Đây là hai cách để làm điều đó trong PostgreSQL. Giả sử đây là bảng của bạn:

CREATE TABLE mytable (
  id SERIAL PRIMARY KEY,
  lastname VARCHAR NOT NULL,
  firstname VARCHAR
);

Bạn có thể làm điều đó trong hai câu lệnh miễn là chúng là các câu lệnh liên tiếp trong cùng một kết nối (điều này sẽ an toàn trong PHP với tính năng gộp kết nối vì PHP không cung cấp kết nối trở lại nhóm cho đến khi tập lệnh của bạn được hoàn tất):

INSERT INTO mytable (lastname, firstname) VALUES ('Washington', 'George');
SELECT lastval();

lastval () cung cấp cho bạn giá trị trình tự được tạo tự động cuối cùng được sử dụng trong kết nối hiện tại.

Cách khác là sử dụng mệnh đề RETURNING của PostgreSQL trên câu lệnh INSERT :

INSERT INTO mytable (lastname) VALUES ('Cher') RETURNING id;

Biểu mẫu này trả về một tập hợp kết quả giống như một câu lệnh SELECT và cũng tiện dụng để trả về bất kỳ loại giá trị mặc định nào được tính toán.


id trả về này sẽ cho trong Đối tượng Resultset phù hợp với java ??
Ankur Loriya

4

Một lưu ý quan trọng là việc sử dụng các truy vấn SQL của nhà cung cấp để truy xuất ID được chèn cuối cùng là an toàn để sử dụng mà không sợ về các kết nối đồng thời.

Tôi luôn nghĩ rằng bạn phải tạo một giao dịch để CHÈN một dòng và sau đó CHỌN ID được chèn cuối cùng để tránh truy xuất ID được chèn bởi khách hàng khác.

Nhưng các truy vấn cụ thể của nhà cung cấp này luôn truy xuất ID được chèn cuối cùng cho kết nối hiện tại với cơ sở dữ liệu . Nó có nghĩa là ID được chèn cuối cùng không thể bị ảnh hưởng bởi các chèn ứng dụng khách khác miễn là chúng sử dụng kết nối cơ sở dữ liệu của riêng mình.


4

Đối với SQL 2005:

Giả sử định nghĩa bảng sau:

CREATE TABLE [dbo].[Test](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [somevalue] [nchar](10) NULL,
) 

Bạn có thể sử dụng như sau:

INSERT INTO Test(somevalue)
OUTPUT INSERTED.ID
VALUES('asdfasdf')

Điều này sẽ trả về giá trị của cột ID.


Điều này vẫn hoạt động tốt trong các phiên bản SQL Server mới hơn.
dub stylee

4

Từ trang web, tôi đã tìm ra những điều sau:

SQL SERVER - @@ IDENTITY so với SCOPE_IDENTITY () so với IDENT_CURRENT - Truy xuất bản ghi nhận dạng được chèn lần cuối vào ngày 25 tháng 3 năm 2007 bởi pinaldave

SELECT @@ IDENTITY Nó trả về giá trị IDENTITY cuối cùng được tạo ra trên một kết nối, bất kể bảng tạo ra giá trị và bất kể phạm vi của câu lệnh tạo ra giá trị. @@ IDENTITY sẽ trả về giá trị nhận dạng cuối cùng được nhập vào bảng trong phiên hiện tại của bạn. Mặc dù @@ IDENTITY bị giới hạn trong phiên hiện tại, nhưng nó không giới hạn trong phạm vi hiện tại. Nếu bạn có trình kích hoạt trên bảng khiến danh tính được tạo trong bảng khác, bạn sẽ nhận được danh tính được tạo sau cùng, ngay cả khi chính trình kích hoạt đã tạo ra nó.

SELECT SCOPE_IDENTITY () Nó trả về giá trị IDENTITY cuối cùng được tạo ra trên một kết nối và bởi một câu lệnh trong cùng phạm vi, bất kể bảng tạo ra giá trị. SCOPE_IDENTITY (), như @@ ​​IDENTITY, sẽ trả về giá trị nhận dạng cuối cùng được tạo trong phiên hiện tại, nhưng nó cũng sẽ giới hạn nó trong phạm vi hiện tại của bạn. Nói cách khác, nó sẽ trả về giá trị nhận dạng cuối cùng mà bạn đã tạo một cách rõ ràng, thay vì bất kỳ danh tính nào được tạo bởi trình kích hoạt hoặc một chức năng do người dùng xác định.

SELECT IDENT_CURRENT ('tablename') Nó trả về giá trị IDENTITY cuối cùng được tạo ra trong một bảng, bất kể kết nối đã tạo ra giá trị và bất kể phạm vi của câu lệnh tạo ra giá trị. 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ụ thể. IDENT_CURRENT trả về giá trị nhận dạng được tạo cho một bảng cụ thể trong bất kỳ phiên nào và bất kỳ phạm vi nào.


Cảm ơn bạn đã giải thích điều này!
doug

2

Hãy nhớ rằng @@ IDENTITY trả về danh tính được tạo gần đây nhất cho kết nối hiện tại của bạn, không nhất thiết là danh tính cho hàng được thêm gần đây trong bảng. Bạn phải luôn sử dụng SCOPE_IDENTITY () để trả lại danh tính của hàng được thêm gần đây.


2

Bạn đang dùng gói dữ liệu nào vậy? Theo như tôi biết, không có phương pháp bất khả tri đối với cơ sở dữ liệu để thực hiện việc này.


2

Đây là cách tôi đã thực hiện bằng cách sử dụng các lệnh được tham số hóa.

MSSQL

 INSERT INTO MyTable (Field1, Field2) VALUES (@Value1, @Value2); 
 SELECT SCOPE_IDENTITY(); 

MySQL

 INSERT INTO MyTable (Field1, Field2) VALUES (?Value1, ?Value2);
 SELECT LAST_INSERT_ID();

2
sql = "INSERT INTO MyTable (Name) VALUES (@Name);" +
      "SELECT CAST(scope_identity() AS int)";
SqlCommand cmd = new SqlCommand(sql, conn);
int newId = (int)cmd.ExecuteScalar();

2

Ms SQL Server: đây là giải pháp tốt ngay cả khi bạn chèn thêm hàng:

 Declare @tblInsertedId table (Id int not null)

 INSERT INTO Test ([Title], [Text])
 OUTPUT inserted.Id INTO @tblInsertedId (Id)
 SELECT [Title], [Text] FROM AnotherTable

 select Id from @tblInsertedId 

1

Câu trả lời của Rob sẽ là câu trả lời khó đoán của nhà cung cấp nhất, nhưng nếu bạn đang sử dụng MySQL thì lựa chọn an toàn và chính xác sẽ là LAST_INSERT_ID()chức năng tích hợp sẵn.


0
SELECT @@Scope_Identity as Id

Ngoài ra còn có danh tính @@, nhưng nếu bạn có trình kích hoạt, nó sẽ trả về kết quả của điều gì đó đã xảy ra trong quá trình kích hoạt, trong đó scope_identity tôn trọng phạm vi của bạn.


0
  1. chèn hàng với một hướng dẫn đã biết.
  2. tìm nạp trường autoId với hướng dẫn này.

Điều này sẽ hoạt động với bất kỳ loại cơ sở dữ liệu nào.


0

Giải pháp Oracle dựa trên môi trường:

CREATE OR REPLACE PACKAGE LAST
AS
ID NUMBER;
FUNCTION IDENT RETURN NUMBER;
END;
/

CREATE OR REPLACE PACKAGE BODY LAST
AS
FUNCTION IDENT RETURN NUMBER IS
    BEGIN
    RETURN ID;
    END;
END;
/


CREATE TABLE Test (
       TestID            INTEGER ,
    Field1      int,
    Field2      int
)


CREATE SEQUENCE Test_seq
/
CREATE OR REPLACE TRIGGER Test_itrig
BEFORE INSERT ON Test
FOR EACH ROW
DECLARE
seq_val number;
BEGIN
IF :new.TestID IS NULL THEN
    SELECT Test_seq.nextval INTO seq_val FROM DUAL;
    :new.TestID := seq_val;
    Last.ID := seq_val;
END IF;
END;
/

To get next identity value:
SELECT LAST.IDENT FROM DUAL


0

Câu trả lời đơn giản nhất:

command.ExecuteScalar()

theo mặc định trả về cột đầu tiên

Loại giá trị trả về: System.Object Cột đầu tiên của hàng đầu tiên trong tập hợp kết quả hoặc tham chiếu rỗng (Không có gì trong Visual Basic) nếu tập kết quả trống. Trả về tối đa 2033 ký tự.

Được sao chép từ MSDN

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.