PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

CHÈN các hàng vào nhiều bảng trong một truy vấn, chọn từ một bảng có liên quan

Phiên bản cuối cùng

... sau một số thông tin thêm từ OP. Hãy xem xét bản trình diễn này:

-- DROP TABLE foo; DROP TABLE bar;

CREATE TEMP TABLE bar (
 id serial PRIMARY KEY  -- using a serial column!
,z  integer NOT NULL
);

CREATE TEMP TABLE foo (
 id     serial PRIMARY KEY  -- using a serial column!
,x      integer NOT NULL
,y      integer NOT NULL
,bar_id integer UNIQUE NOT NULL REFERENCES bar(id)
);

Chèn giá trị - bar đầu tiên.
Nó sẽ rất hữu ích nếu bạn đã cung cấp dữ liệu thử nghiệm trong câu hỏi của mình như thế này!

INSERT INTO bar (id,z) VALUES
 (100, 7)
,(101,16)
,(102,21);

INSERT INTO foo (id, x, y, bar_id) VALUES
 (1, 3,4,100)
,(2, 9,6,101)
,(3,18,0,102);

Đặt các chuỗi thành giá trị hiện tại nếu không chúng tôi nhận được các lỗi vi phạm chính trùng lặp:

SELECT setval('foo_id_seq', 3);
SELECT setval('bar_id_seq', 102);

Séc:

-- SELECT nextval('foo_id_seq')
-- SELECT nextval('bar_id_seq')
-- SELECT * from bar;
-- SELECT * from foo;

Truy vấn:

WITH a AS (
    SELECT f.x, f.y, bar_id, b.z
    FROM   foo f
    JOIN   bar b ON b.id = f.bar_id
    WHERE  x > 3
    ),b AS (
    INSERT INTO bar (z)
    SELECT z
    FROM   a
    RETURNING z, id AS bar_id
    )
INSERT INTO foo (x, y, bar_id)
SELECT a.x, a.y, b.bar_id
FROM   a
JOIN   b USING (z);

Điều này sẽ thực hiện những gì mà bản cập nhật cuối cùng của bạn mô tả.

Truy vấn giả định rằng z UNIQUE . Nếu z không phải là duy nhất, nó trở nên phức tạp hơn. Tham khảo Truy vấn 2 trong câu trả lời liên quan này để biết giải pháp sẵn sàng bằng cách sử dụng hàm window row_number() trong trường hợp này.

Ngoài ra, hãy xem xét thay thế mối quan hệ 1:1 giữa foobar với một bảng thống nhất.

CTE sửa đổi dữ liệu

Câu trả lời thứ hai sau khi biết thêm thông tin.

Nếu bạn muốn thêm hàng vào foo bar trong một truy vấn duy nhất, bạn có thể sử dụng CTE sửa đổi dữ liệu kể từ PostgreSQL 9.1 :

WITH x AS (
    INSERT INTO bar (col1, col2)
    SELECT f.col1, f.col2
    FROM   foo f
    WHERE  f.id BETWEEN 12 AND 23 -- some filter
    RETURNING col1, col2, bar_id  -- assuming bar_id is a serial column
    )
INSERT INTO foo (col1, col2, bar_id)
SELECT col1, col2, bar_id
FROM   x;

Tôi lấy các giá trị từ foo , chèn chúng vào bar , chúng được trả về cùng nhau bằng bar_id được tạo tự động và chèn that thành foo . Bạn cũng có thể sử dụng bất kỳ dữ liệu nào khác.

Đây là bản demo hoạt động để chơi trên sqlfiddle.

Kiến thức cơ bản

Câu trả lời gốc với thông tin cơ bản trước khi làm rõ.
Dạng cơ bản là:

INSERT INTO foo (...)
SELECT ... FROM foo WHERE ...

Không cần dấu ngoặc đơn. Bạn có thể làm tương tự với bất kỳ bảng nào

INSERT INTO foo (...)
SELECT ... FROM bar WHERE ...

Và bạn có thể tham gia vào bảng mà bạn chèn vào trong phần CHỌN:

INSERT INTO foo (...)
SELECT f.col1, f.col2, .. , b.bar_id
FROM   foo f
JOIN   bar b USING (foo_id);  -- present in foo and bar

Nó chỉ là một CHỌN giống như bất kỳ lệnh nào khác - có thể bao gồm bảng bạn đang chèn vào. Các hàng được đọc trước tiên, sau đó được chèn vào.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mệnh đề IN với NULL hoặc IS NULL

  2. mã hóa UTF8 không khớp với ngôn ngữ en_US; cài đặt LC_CTYPE đã chọn yêu cầu mã hóa LATIN1

  3. Làm thế nào để cài đặt libpq-fe.h?

  4. Trong Postgresql, buộc duy nhất trên sự kết hợp của hai cột

  5. Dấu hai chấm (::) ký hiệu trong SQL