ฉันสามารถใช้ค่าส่งกลับของ INSERT … RETURNING ใน INSERT อื่นได้หรือไม่


87

สิ่งนี้เป็นไปได้หรือไม่?

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

เช่นเดียวกับการใช้ค่า return เป็นค่าเพื่อแทรกแถวในตารางที่สองโดยอ้างอิงกับตารางแรก?

คำตอบ:


106

คุณสามารถทำได้โดยเริ่มจาก Postgres 9.1:

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

ในขณะเดียวกันหากคุณสนใจเฉพาะรหัสคุณสามารถทำได้โดยใช้ทริกเกอร์:

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
จะแทรกค่าข้าง id ที่ส่งคืนได้อย่างไร ตัวอย่างเช่น INSERT INTO TABLE2 (val1, val2, val3) (1, 2, SELECT id FROM row)
Mahmoud Hanafy

@MahmoudHanafy: การแทนที่rowsด้วย(some_query returning ...)อาจใช้งานได้ในปัจจุบัน (ยังไม่ได้ลอง)
Denis de Bernardy

2
@MahmoudHanafy: ในการแทรกค่าข้าง id ที่ส่งคืนคุณสามารถทำสิ่งนี้: INSERT INTO TABLE2 (val1, val2, val3) SELECT id, 1, 2 FROM แถว
Bhindi

โหวตแล้ว! นี่คือความหมายของอะตอมหากการแทรกครั้งแรกสำเร็จและอันที่สองไม่เกิดอะไรขึ้น?
PirateApp

2
@PirateApp เพิ่งทดสอบ! v12.4 INSERT แรกถูก
ย้อนกลับ

58

แนวทางปฏิบัติที่ดีที่สุดสำหรับสถานการณ์นี้ ใช้RETURNING … INTO.

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

โปรดทราบว่านี่สำหรับ PLPGSQL


3
นี่เป็นเรื่องจริงหรือ? RETURNING ... INTOส่วนหนึ่งของเอกสารที่คุณเชื่อมโยงไปยังดูเหมือนว่าจะพูดถึง
Alec

4
@Alec: ฉันพบเอกสารนี้ในคำตอบนี้
Bart Hofland

@PedroD: มันทำ
Bart Hofland

13

สอดคล้องกับคำตอบของ Denis de Bernardy ..

หากคุณต้องการส่งคืน id ในภายหลังเช่นกันและต้องการแทรกสิ่งต่างๆเพิ่มเติมใน 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 $$;

ทดสอบกับ psql (10.3, เซิร์ฟเวอร์ 9.6.8)


8

คุณสามารถใช้lastval()ฟังก์ชัน:

ส่งคืนค่าที่ได้รับล่าสุดnextvalสำหรับลำดับใด ๆ

ดังนั้นสิ่งนี้:

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

สิ่งนี้จะทำงานได้ดีตราบเท่าที่ไม่มีใครเรียกnextval()ลำดับอื่น ๆ (ในเซสชันปัจจุบัน) ระหว่าง INSERT ของคุณ

ดังที่เดนิสระบุไว้ด้านล่างและฉันเตือนเกี่ยวกับข้างต้นการใช้lastval()อาจทำให้คุณมีปัญหาหากมีการเข้าถึงลำดับอื่นโดยใช้nextval()ระหว่าง INSERT ของคุณ สิ่งนี้อาจเกิดขึ้นได้หากมีทริกเกอร์ INSERT ที่เรียกTable1ด้วยตนเองnextval()ตามลำดับหรือมีแนวโน้มมากขึ้นที่จะแทรกบนตารางด้วยคีย์SERIALหรือBIGSERIALคีย์หลัก หากคุณต้องการที่จะหวาดระแวงจริงๆ (เป็นสิ่งที่ดีจริงๆแล้วพวกเขาคือคุณที่จะทำให้คุณได้รับหลังจากนั้น) คุณสามารถใช้ได้currval()แต่คุณต้องรู้ชื่อของลำดับที่เกี่ยวข้อง:

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

ลำดับที่สร้างขึ้นโดยอัตโนมัติมักจะเป็นชื่อt_c_seqที่tเป็นชื่อตารางและcเป็นชื่อคอลัมน์ แต่คุณสามารถหาโดยจะเป็นpsqlและพูดว่า:

=> \d table_name;

จากนั้นดูค่าเริ่มต้นสำหรับคอลัมน์ที่เป็นปัญหาเช่น:

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

FYI: lastval()มีมากกว่าหรือน้อยกว่ารุ่น PostgreSQL ของของ LAST_INSERT_IDMySQL ฉันพูดถึงเรื่องนี้เพราะผู้คนจำนวนมากคุ้นเคยกับ MySQL มากกว่า PostgreSQL ดังนั้นการเชื่อมโยงlastval()กับสิ่งที่คุ้นเคยอาจทำให้เกิดความกระจ่าง


2
ควรใช้ currval () ดีกว่าในกรณีที่ทริกเกอร์บน table1 แทรกตามมา
Denis de Bernardy

@ เดนิส: จริง แต่คุณต้องมีชื่อของลำดับ ฉันจะเพิ่มการอัปเดตเล็กน้อยให้กับเอฟเฟกต์นั้นเพื่อให้ครอบคลุมฐานทั้งหมด
สั้นเกินไป

LASTVAL () และ CURRVAL () ใช้งานได้กับการเชื่อมต่อฐานข้อมูลปัจจุบันไม่ใช่สำหรับการเชื่อมต่ออื่น ๆ ผู้ใช้รายอื่นสามารถอัปเดตลำดับตามเวลาที่กำหนดซึ่งจะไม่เปลี่ยนแปลงผลลัพธ์ของคุณ อย่ากังวลกับคนอื่นพวกเขาจะไม่เปลี่ยนผลลัพธ์ของคุณสำหรับ LASTVAL และ / ของ CURRVAL ไม่สามารถใช้ LASTVAL และ CURRVAL ได้เลยเมื่อใช้ Connectionpool โดยไม่มี TRANSACTION นั่นคือเมื่อเกิดสิ่งผิดปกติ: คุณไม่ได้ควบคุมการเชื่อมต่อฐานข้อมูล
Frank Heikens

1
@ แฟรงค์: ใช่พวกเขาทั้งหมดเฉพาะเซสชัน แต่ปัญหาlastvalคืออาจมี INSERT ตามลำดับที่อยู่ด้านหลังของคุณจากทริกเกอร์ AFTER INSERT บน Table1 นั่นจะอยู่ในเซสชันปัจจุบันและอาจมีการเปลี่ยนแปลงlastval()เมื่อคุณไม่คาดหวัง
สั้นเกินไป

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 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.