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?
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?
Câu trả lời:
@@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()
Đâ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();
Đ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.
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();
}
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
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.
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.
Đố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.
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.
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.
Đâ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();
sql = "INSERT INTO MyTable (Name) VALUES (@Name);" +
"SELECT CAST(scope_identity() AS int)";
SqlCommand cmd = new SqlCommand(sql, conn);
int newId = (int)cmd.ExecuteScalar();
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
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.
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.
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
Trong TransactSQL, bạn có thể sử dụng mệnh đề OUTPUT để đạt được điều đó.
INSERT INTO my_table(col1,col2,col3) OUTPUT INSERTED.id VALUES('col1Value','col2Value','col3Value')
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