Trong PostgreSQL, làm cách nào để lấy id cuối cùng được chèn vào bảng?
Trong MS SQL có SCOPE_IDENTITY ().
Xin đừng khuyên tôi sử dụng một cái gì đó như thế này:
select max(id) from table
Trong PostgreSQL, làm cách nào để lấy id cuối cùng được chèn vào bảng?
Trong MS SQL có SCOPE_IDENTITY ().
Xin đừng khuyên tôi sử dụng một cái gì đó như thế này:
select max(id) from table
Câu trả lời:
( tl;dr
: tùy chọn goto 3: XÁC NHẬN với RETURNING)
Hãy nhớ lại rằng trong postgresql không có khái niệm "id" cho các bảng, chỉ là các chuỗi (thường không nhất thiết được sử dụng làm giá trị mặc định cho các khóa chính thay thế, với kiểu giả SERIAL ).
Nếu bạn quan tâm đến việc lấy id của một hàng mới được chèn, có một số cách:
Tùy chọn 1 : CURRVAL(<sequence name>);
.
Ví dụ:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
Tên của chuỗi phải được biết, nó thực sự tùy ý; trong ví dụ này, chúng tôi giả sử rằng bảng persons
có một id
cột được tạo bằng kiểu SERIAL
giả. Để tránh phụ thuộc vào điều này và cảm thấy sạch sẽ hơn, bạn có thể sử dụng thay thế pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Hãy cẩn thận: currval()
chỉ hoạt động sau khi một INSERT
(đã thực hiện nextval()
), trong cùng một phiên .
Lựa chọn 2: LASTVAL();
Điều này tương tự như trước đây, chỉ là bạn không cần chỉ định tên trình tự: nó tìm chuỗi được sửa đổi gần đây nhất (luôn bên trong phiên của bạn, cùng cảnh báo như trên).
Cả hai CURRVAL
và LASTVAL
hoàn toàn đồng thời an toàn. Hành vi của chuỗi trong PG được thiết kế sao cho các phiên khác nhau sẽ không can thiệp, do đó không có rủi ro về điều kiện chủng tộc (nếu một phiên khác chèn một hàng khác giữa INSERT và CHỌN của tôi, tôi vẫn nhận được giá trị chính xác của mình).
Tuy nhiên, họ có một vấn đề tiềm năng tinh tế. Nếu cơ sở dữ liệu có một số TRIGGER (hoặc RULE) mà khi chèn vào persons
bảng sẽ tạo thêm một số phần bổ sung trong các bảng khác ... thì LASTVAL
có thể sẽ cung cấp cho chúng ta giá trị sai. Vấn đề thậm chí có thể xảy ra với CURRVAL
, nếu việc chèn thêm được thực hiện trong cùng một persons
bảng (điều này ít thông thường hơn, nhưng rủi ro vẫn tồn tại).
Tùy chọn 3: INSERT
vớiRETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Đây là cách sạch nhất, hiệu quả và an toàn để lấy id. Nó không có bất kỳ rủi ro nào trước đó.
Hạn chế? Hầu như không có: bạn có thể cần phải sửa đổi cách bạn gọi câu lệnh INSERT của mình (trong trường hợp xấu nhất, có lẽ lớp API hoặc DB của bạn không mong đợi INSERT trả về giá trị); đó không phải là SQL chuẩn (ai quan tâm); nó có sẵn kể từ Postgresql 8.2 (tháng 12 năm 2006 ...)
Kết luận: Nếu bạn có thể, hãy chọn tùy chọn 3. Ở nơi khác, thích 1.
Lưu ý: tất cả các phương thức này đều vô dụng nếu bạn dự định lấy id được chèn cuối cùng trên toàn cầu (không nhất thiết phải theo phiên của bạn). Đối với điều này, bạn phải dùng đến SELECT max(id) FROM table
(tất nhiên, điều này sẽ không đọc các phần chèn không được cam kết từ các giao dịch khác).
Ngược lại, bạn không bao giờ nên sử dụng SELECT max(id) FROM table
thay vào một trong 3 tùy chọn ở trên, để lấy id vừa được tạo bởi INSERT
câu lệnh của bạn , bởi vì (ngoài hiệu suất), điều này không an toàn đồng thời: giữa bạn INSERT
và SELECT
phiên khác của bạn có thể đã chèn một bản ghi khác.
SELECT max(id)
tiếc là không thực hiện công việc ngay khi bạn bắt đầu xóa hàng.
1,2,3,4,5
và xóa hàng 4 và 5, ID được chèn cuối cùng vẫn là 5, nhưng max()
trả về 3.
RETURNING id;
để chèn cái này vào một bảng khác sẽ được hoan nghênh!
RETURNING id
trong tập lệnh SQL được cung cấp cho psql
công cụ dòng lệnh?
Xem mệnh đề RETURNING của câu lệnh INSERT . Về cơ bản, INSERT nhân đôi như một truy vấn và trả lại cho bạn giá trị được chèn.
insert into names (firstname, lastname) values ('john', 'smith') returning id;
thì nó chỉ đơn giản xuất ra id giống như khi bạn chạy select id from names where id=$lastid
trực tiếp. Nếu bạn muốn lưu trả về vào một biến aa , thì insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
Nếu câu lệnh chứa trả về là câu lệnh cuối cùng trong một hàm , thì toàn bộ id đang returning
được trả về bởi toàn bộ hàm.
bạn có thể sử dụng mệnh đề RETURNING trong câu lệnh INSERT, giống như sau
wgzhao=# create table foo(id int,name text);
CREATE TABLE
wgzhao=# insert into foo values(1,'wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into foo values(3,'wgzhao') returning id;
id
----
3
(1 row)
INSERT 0 1
wgzhao=# create table bar(id serial,name text);
CREATE TABLE
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
2
(1 row)
INSERT 0
Câu trả lời của Leonbloy khá đầy đủ. Tôi sẽ chỉ thêm trường hợp đặc biệt trong đó người ta cần lấy giá trị được chèn cuối cùng từ bên trong hàm PL / pgQuery trong đó TÙY CHỌN 3 không khớp chính xác.
Ví dụ: nếu chúng ta có các bảng sau:
CREATE TABLE person(
id serial,
lastname character varying (50),
firstname character varying (50),
CONSTRAINT person_pk PRIMARY KEY (id)
);
CREATE TABLE client (
id integer,
CONSTRAINT client_pk PRIMARY KEY (id),
CONSTRAINT fk_client_person FOREIGN KEY (id)
REFERENCES person (id) MATCH SIMPLE
);
Nếu chúng ta cần chèn một bản ghi khách hàng, chúng ta phải tham khảo một bản ghi cá nhân. Nhưng giả sử chúng ta muốn tạo ra một hàm PL / pgSQL chèn một bản ghi mới vào máy khách nhưng cũng đảm nhiệm việc chèn bản ghi người mới. Để làm được điều đó, chúng ta phải sử dụng một biến thể nhỏ của TÙY CHỌN 3 của leonbloy:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
Lưu ý rằng có hai mệnh đề INTO. Do đó, hàm PL / pgSQL sẽ được định nghĩa như sau:
CREATE OR REPLACE FUNCTION new_client(lastn character varying, firstn character varying)
RETURNS integer AS
$BODY$
DECLARE
v_id integer;
BEGIN
-- Inserts the new person record and retrieves the last inserted id
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO v_id;
-- Inserts the new client and references the inserted person
INSERT INTO client(id) VALUES (v_id);
-- Return the new id so we can use it in a select clause or return the new id into the user application
RETURN v_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Bây giờ chúng ta có thể chèn dữ liệu mới bằng cách sử dụng:
SELECT new_client('Smith', 'John');
hoặc là
SELECT * FROM new_client('Smith', 'John');
Và chúng tôi nhận được id mới được tạo.
new_client
integer
----------
1
Xem ví dụ dưới đây
CREATE TABLE users (
-- make the "id" column a primary key; this also creates
-- a UNIQUE constraint and a b+-tree index on the column
id SERIAL PRIMARY KEY,
name TEXT,
age INT4
);
INSERT INTO users (name, age) VALUES ('Mozart', 20);
Sau đó, để nhận id được chèn lần cuối, hãy sử dụng cái này cho bảng "người dùng" tên cột seq "id"
SELECT currval(pg_get_serial_sequence('users', 'id'));
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
Bạn cần cung cấp tên bảng và tên cột của khóa học.
Điều này sẽ dành cho phiên / kết nối hiện tại http://www.postgresql.org/docs/8.3/static/fifts- resultence.html
Thử cái này:
select nextval('my_seq_name'); // Returns next value
Nếu giá trị này trả về 1 (hoặc bất cứ điều gì là start_value cho chuỗi của bạn), thì hãy đặt lại chuỗi đó về giá trị ban đầu, chuyển cờ sai:
select setval('my_seq_name', 1, false);
Nếu không thì,
select setval('my_seq_name', nextValue - 1, true);
Điều này sẽ khôi phục giá trị chuỗi về trạng thái ban đầu và "setval" sẽ trả về với giá trị chuỗi bạn đang tìm kiếm.
Postgres có một cơ chế sẵn có cho cùng, trong cùng một truy vấn sẽ trả về id hoặc bất cứ điều gì bạn muốn truy vấn trả về. đây là một ví dụ. Hãy xem xét bạn có một bảng được tạo có 2 cột cột1 và cột2 và bạn muốn cột 1 được trả về sau mỗi lần chèn.
# create table users_table(id serial not null primary key, name character varying);
CREATE TABLE
#insert into users_table(name) VALUES ('Jon Snow') RETURNING id;
id
----
1
(1 row)
# insert into users_table(name) VALUES ('Arya Stark') RETURNING id;
id
----
2
(1 row)
Tôi đã có vấn đề này với Java và Postgres. Tôi đã sửa nó bằng cách cập nhật phiên bản Connector-J mới.
postgresql-9.2-1002.jdbc4.jar
https://jdbc.postgresql.org/doad.html : Phiên bản 42.2.12