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

PostgreSQL - chèn các hàng dựa trên lựa chọn từ một bảng khác và cập nhật FK trong bảng đó với các hàng mới được chèn

Có một số cách để giải quyết vấn đề.

1. tạm thời thêm một cột

Như những người khác đã đề cập, cách đơn giản là thêm tạm thời một cột reminder_id đến dateset . Điền nó với IDs ban đầu từ reminder bàn. Sử dụng nó để tham gia reminder với dateset bàn. Bỏ cột tạm thời.

2. khi bắt đầu là duy nhất

Nếu các giá trị của start cột là duy nhất, bạn có thể thực hiện điều đó mà không cần thêm cột bằng cách tham gia reminder bảng với dateset trên start cột.

INSERT INTO dateset (start)
SELECT start FROM reminder;

WITH
CTE_Joined
AS
(
    SELECT
        reminder.id AS reminder_id
        ,reminder.dateset_id AS old_dateset_id
        ,dateset.id AS new_dateset_id
    FROM
        reminder
        INNER JOIN dateset ON dateset.start = reminder.start
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

3. khi bắt đầu không phải là duy nhất

Có thể làm điều đó mà không cần cột tạm thời ngay cả trong trường hợp này. Ý tưởng chính là sau đây. Hãy xem ví dụ này:

Chúng tôi có hai hàng trong reminder với cùng một start giá trị và ID 3 và 7:

reminder
id    start         dateset_id
3     2015-01-01    NULL
7     2015-01-01    NULL

Sau khi chúng tôi chèn chúng vào dateset , sẽ có các ID mới được tạo, ví dụ:1 và 2:

dateset
id    start
1     2015-01-01
2     2015-01-01

Không thực sự quan trọng bằng cách nào chúng ta liên kết hai hàng này. Kết quả cuối cùng có thể là

reminder
id    start         dateset_id
3     2015-01-01    1
7     2015-01-01    2

hoặc

reminder
id    start         dateset_id
3     2015-01-01    2
7     2015-01-01    1

Cả hai biến thể này đều đúng. Điều này đưa chúng ta đến giải pháp sau.

Chỉ cần chèn tất cả các hàng trước.

INSERT INTO dateset (start)
SELECT start FROM reminder;

Khớp / nối hai bảng trên start cột biết rằng nó không phải là duy nhất. "Làm cho nó" trở thành duy nhất bằng cách thêm ROW_NUMBER và nối bằng hai cột. Có thể làm cho truy vấn ngắn hơn, nhưng tôi đã viết rõ ràng từng bước:

WITH
CTE_reminder_rn
AS
(
    SELECT
        id
        ,start
        ,dateset_id
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM reminder
)
,CTE_dateset_rn
AS
(
    SELECT
        id
        ,start
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM dateset
)
,CTE_Joined
AS
(
    SELECT
        CTE_reminder_rn.id AS reminder_id
        ,CTE_reminder_rn.dateset_id AS old_dateset_id
        ,CTE_dateset_rn.id AS new_dateset_id
    FROM
        CTE_reminder_rn
        INNER JOIN CTE_dateset_rn ON 
            CTE_dateset_rn.start = CTE_reminder_rn.start AND
            CTE_dateset_rn.rn = CTE_reminder_rn.rn
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

Tôi hy vọng nó rõ ràng từ mã những gì nó làm, đặc biệt là khi bạn so sánh nó với phiên bản đơn giản hơn mà không có ROW_NUMBER . Rõ ràng, giải pháp phức tạp sẽ hoạt động ngay cả khi start là duy nhất, nhưng nó không hiệu quả như một giải pháp đơn giản.

Giải pháp này giả định rằng dateset trống trước quá trình này.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL tìm tất cả các kết hợp có thể có (hoán vị) trong truy vấn đệ quy

  2. Mảng đa chiều PostgreSQL

  3. Hibernate Native Query vấn đề với các tham số được đặt tên

  4. Dấu thời gian jOOQ được lưu trữ với độ lệch múi giờ cục bộ

  5. Làm thế nào để sử dụng Postgres jsonb '?' toán tử trong Laravel với hỗ trợ chỉ mục?