Tôi có thể sử dụng giá trị trả về của INSERT… RETURNING trong một INSERT khác không?


86

Có phải bất cư thứ gì như thế này đều được?

INSERT INTO Table2 (val)
VALUES ((INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id));

như sử dụng giá trị trả về làm giá trị để chèn một hàng trong bảng thứ hai với tham chiếu đến bảng đầu tiên?

Câu trả lời:


104

Bạn có thể làm như vậy bắt đầu với Postgres 9.1:

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val)
SELECT id
FROM rows

Trong khi đó, nếu bạn chỉ quan tâm đến id, bạn có thể làm như vậy với trình kích hoạt:

create function t1_ins_into_t2()
  returns trigger
as $$
begin
  insert into table2 (val) values (new.id);
  return new;
end;
$$ language plpgsql;

create trigger t1_ins_into_t2
  after insert on table1
for each row
execute procedure t1_ins_into_t2();

1
Làm cách nào để chèn các giá trị bên cạnh id trả về? ví dụ: INSERT INTO table2 (VAL1, VAL2, val3) (1, 2, SELECT id TỪ hàng)
Mahmoud Hanafy

@MahmoudHanafy: thay thế rowsbằng (some_query returning ...)có thể hoạt động hiện nay (chưa thử).
Denis de Bernardy

2
@MahmoudHanafy: Để chèn các giá trị bên cạnh id trở về bạn có thể làm một cái gì đó như thế này: INSERT INTO table2 (VAL1, VAL2, val3) SELECT id, 1, 2 TỪ hàng
Bhindi

ủng hộ! nguyên tử này có nghĩa là nếu lần chèn đầu tiên thành công và lần chèn thứ hai thì không điều gì xảy ra sau đó?
PirateApp

2
@PirateApp Vừa được thử nghiệm! v12.4. INSERT đầu tiên thực sự được hỗ trợ cuộn nếu cái thứ hai không thành công, nhưng chuỗi / tự động tăng thêm của INSERT đầu tiên bị bỏ qua
Madacol

57

Cách tốt nhất cho tình huống này. Sử dụng RETURNING … INTO.

INSERT INTO teams VALUES (...) RETURNING id INTO last_id;

Lưu ý điều này dành cho PLPGSQL


3
Đây có thực sự là một điều? Dường như không có phần nào của tài liệu bạn liên kết đến đề cập đến RETURNING ... INTO.
Alec

4
@Alec: Tôi tìm thấy tài liệu này trong câu trả lời này .
Bart Hofland

@PedroD: Đúng vậy.
Bart Hofland

13

Phù hợp với câu trả lời của Denis de Bernardy ..

Nếu bạn muốn id cũng được trả về sau đó và muốn chèn nhiều thứ hơn vào Table2:

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val, val2, val3)
SELECT id, 'val2value', 'val3value'
FROM rows
RETURNING val

10
DO $$
DECLARE tableId integer;
BEGIN
  INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id INTO tableId;
  INSERT INTO Table2 (val) VALUES (tableId);
END $$;

Đã kiểm tra với psql (10.3, máy chủ 9.6.8)


8

Bạn có thể sử dụng lastval()chức năng:

Giá trị trả về thu được gần đây nhất nextvalcho bất kỳ chuỗi nào

Vì vậy, một cái gì đó như thế này:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (lastval());

Điều này sẽ hoạt động tốt miễn là không có ai gọi nextval()đến bất kỳ chuỗi nào khác (trong phiên hiện tại) giữa các INSERT của bạn.

Như Denis đã lưu ý bên dưới và tôi đã cảnh báo ở trên, việc sử dụng lastval()có thể khiến bạn gặp rắc rối nếu một chuỗi khác được truy cập bằng cách sử dụng nextval()giữa các INSERT của bạn. Điều này có thể xảy ra nếu có một kích hoạt INSERT trên Table1đó được gọi theo cách thủ công nextval()trên một chuỗi hoặc nhiều khả năng hơn đã thực hiện INSERT trên bảng có khóa SERIALhoặcBIGSERIAL khóa chính. Nếu bạn muốn thực sự hoang tưởng (một điều tốt, họ thực sự là bạn để có được bạn), thì bạn có thể sử dụng currval()nhưng bạn cần biết tên của chuỗi liên quan:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (currval('Table1_id_seq'::regclass));

Trình tự tự động tạo ra thường được đặt tên theo t_c_seqnơi tlà tên bảng và clà tên cột nhưng bạn luôn có thể tìm hiểu bằng cách đi sâu vào psqlvà nói:

=> \d table_name;

và sau đó xem xét giá trị mặc định cho cột được đề cập, ví dụ:

id | integer | not null default nextval('people_id_seq'::regclass)

FYI: lastval()ít nhiều là phiên bản PostgreSQL của MySQL LAST_INSERT_ID. Tôi chỉ đề cập đến vấn đề này vì nhiều người quen thuộc với MySQL hơn PostgreSQL nên việc liên kết lastval()đến một thứ quen thuộc có thể làm rõ mọi thứ.


2
Tuy nhiên, tốt hơn hãy sử dụng currval () trong trường hợp trình kích hoạt trên table1 thực hiện các lần chèn tiếp theo.
Denis de Bernardy

@Denis: Đúng, nhưng sau đó bạn cần tên của chuỗi. Tôi sẽ thêm một chút cập nhật cho hiệu ứng đó chỉ để bao phủ tất cả các cơ sở.
mu quá ngắn

LASTVAL () và CURRVAL () đều hoạt động cho kết nối cơ sở dữ liệu hiện tại, không cho các kết nối khác. Những người dùng khác có thể cập nhật trình tự cùng một lúc, điều này sẽ không thay đổi kết quả của bạn. Đừng lo lắng về những người khác, họ sẽ không bao giờ thay đổi kết quả của bạn cho LASTVAL và / của CURRVAL. Không thể sử dụng LASTVAL và CURRVAL khi sử dụng nhóm kết nối mà không có GIAO DỊCH, đó là khi mọi thứ xảy ra: Bạn không kiểm soát kết nối cơ sở dữ liệu.
Frank Heikens

1
@Frank: Vâng, tất cả chúng đều dành riêng cho từng phiên nhưng vấn đề lastvallà có thể có một trình tự INSERT sau lưng bạn từ một kích hoạt SAU KHI CHÈN trên Table1. Điều đó sẽ có trong phiên hiện tại và có lẽ sẽ thay đổi lastval()khi bạn không mong đợi.
mu quá ngắn

1

table_ex

id default nextval ('table_id_seq' :: regclass),

camp1 varchar

camp2 varchar

INSERT INTO table_ex(camp1,camp2) VALUES ('xxx','123') RETURNING id 
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.