sql >> Database teknologi >  >> RDS >> PostgreSQL

PostgreSQL - indsæt rækker baseret på valg fra en anden tabel, og opdater en FK i den tabel med de nyligt indsatte rækker

Der er flere måder at løse problemet på.

1. midlertidigt tilføje en kolonne

Som andre nævnte, er den enkle måde midlertidigt at tilføje en kolonne reminder_id til dateset . Udfyld den med originale IDs fra reminder bord. Brug den til at deltage i reminder med dateset bord. Slip den midlertidige kolonne.

2. når start er unik

Hvis værdierne for start kolonne er unik, det er muligt at gøre det uden ekstra kolonne ved at deltage i reminder tabel med dateset tabel på start kolonne.

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. når start ikke er unik

Det er muligt at gøre det uden midlertidig kolonne selv i dette tilfælde. Hovedideen er følgende. Lad os se på dette eksempel:

Vi har to rækker i reminder med den samme start værdi og ID'er 3 og 7:

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

Efter vi har indsat dem i dateset , vil der blive genereret nye ID'er, f.eks. 1 og 2:

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

Det er lige meget, hvordan vi forbinder disse to rækker. Slutresultatet kunne være

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

eller

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

Begge disse varianter er korrekte. Hvilket bringer os til følgende løsning.

Indsæt blot alle rækker først.

INSERT INTO dateset (start)
SELECT start FROM reminder;

Match/forbind to borde på start kolonne vel vidende, at det ikke er unikt. "Gør det" unikt ved at tilføje ROW_NUMBER og forbindes med to søjler. Det er muligt at gøre forespørgslen kortere, men jeg har præciseret hvert trin eksplicit:

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
;

Jeg håber, det fremgår tydeligt af koden, hvad den gør, især når du sammenligner den med den enklere version uden ROW_NUMBER . Det er klart, at den komplekse løsning virker, selvom start er unik, men den er ikke så effektiv som en simpel løsning.

Denne løsning antager, at dateset er tom før denne proces.



  1. får en fejl under definering af hændelsesnavnet på mysqlworkbench 5.5

  2. Mareridt java læk... med loop og jdbc

  3. Matrix multiplikation i python og mysql

  4. Hvordan dybkopierer jeg et sæt data og ændrer FK-referencer til at pege på alle kopierne?