PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL - Zeilen basierend auf der Auswahl aus einer anderen Tabelle einfügen und einen FK in dieser Tabelle mit den neu eingefügten Zeilen aktualisieren

Es gibt mehrere Möglichkeiten, das Problem zu lösen.

1. vorübergehend eine Spalte hinzufügen

Wie bereits erwähnt, ist der direkte Weg, vorübergehend eine Spalte reminder_id hinzuzufügen zum dateset . Füllen Sie es mit den ursprünglichen IDs von reminder Tisch. Verwenden Sie es, um reminder beizutreten mit dem dateset Tisch. Löschen Sie die temporäre Spalte.

2. wenn start eindeutig ist

Wenn Werte von start Spalte einzigartig ist, ist es möglich, sie ohne zusätzliche Spalte zu machen, indem man reminder hinzufügt Tabelle mit dem dateset Tabelle am start Spalte.

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. wenn start nicht eindeutig ist

Auch in diesem Fall ist es möglich, auf eine temporäre Spalte zu verzichten. Die Hauptidee ist die folgende. Schauen wir uns dieses Beispiel an:

Wir haben zwei Zeilen in reminder mit demselben start Wert und IDs 3 und 7:

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

Nachdem wir sie in das dateset eingefügt haben , werden neue IDs generiert, zum Beispiel 1 und 2:

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

Es spielt keine Rolle, wie wir diese beiden Zeilen verknüpfen. Das Endergebnis könnte

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

oder

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

Beide Varianten sind richtig. Das bringt uns zu folgender Lösung.

Einfach alle Zeilen zuerst einfügen.

INSERT INTO dateset (start)
SELECT start FROM reminder;

Ordnen Sie zwei Tische bei start zu/verbinden Sie sie Spalte in dem Wissen, dass sie nicht eindeutig ist. "Machen Sie es" einzigartig, indem Sie ROW_NUMBER hinzufügen und Verbinden durch zwei Spalten. Es ist möglich, die Abfrage zu verkürzen, aber ich habe jeden Schritt explizit aufgeführt:

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
;

Ich hoffe, es ist aus dem Code ersichtlich, was er tut, besonders wenn man ihn mit der einfacheren Version ohne ROW_NUMBER vergleicht . Offensichtlich funktioniert die komplexe Lösung auch, wenn start ist einzigartig, aber nicht so effizient wie eine einfache Lösung.

Diese Lösung geht davon aus, dass dateset ist vor diesem Vorgang leer.