PostgreSQL - fügt Zeilen basierend auf Auswahl aus einer anderen Tabelle ein und aktualisiert einen FK in dieser Tabelle mit den neu eingefügten Zeilen

8

Ich mache eine Datenmigration zwischen zwei Tabellen (spaltet eine verwandte Tabelle aus). Die vorhandene Tabelle ist reminders und hat eine start -Spalte und eine neu hinzugefügte dateset_id -Spalte, die auf eine neue dateset -Tabelle verweist, die auch eine start -Spalte enthält. Für jede Zeile in reminders möchte ich INSERT eine neue Zeile in dateset mit dem Wert start übernehmen und UPDATE die entsprechende Zeile in reminders mit der neu eingefügten dateset ID .

Hier ist die SQL, die ich versucht habe:

%Vor%

Ich erhalte den Fehler missing FROM-clause entry for table "reminder" , weil ich die Spalte reminder.id in die RETURNING -Klausel einfüge, sie aber nicht für die Einfügung auswähle. Das macht Sinn, aber ich kann nicht herausfinden, wie ich die Abfrage modifizieren soll, um das zu tun, was ich brauche. Gibt es einen völlig anderen Ansatz, den ich vermisse?

    
Carl Meyer 05.02.2015, 01:33
quelle

4 Antworten

9

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

1. Fügen Sie vorübergehend eine Spalte hinzu

Wie bereits erwähnt, besteht der direkte Weg darin, vorübergehend eine Spalte reminder_id zum dateset hinzuzufügen. Füllen Sie es mit dem ursprünglichen IDs aus reminder table. Verwenden Sie es, um reminder mit der Tabelle dateset zu verbinden. Löschen Sie die temporäre Spalte.

2. Wenn start einzigartig ist

Wenn die Werte der Spalte start eindeutig sind, ist es möglich, sie ohne zusätzliche Spalte auszuführen, indem Sie die Tabelle reminder mit der Tabelle dateset in der Spalte start verbinden.

%Vor%

3. Wenn start nicht eindeutig ist

Es ist sogar in diesem Fall möglich, es ohne temporäre Spalte zu machen. Die Hauptidee ist folgendes. Sehen wir uns dieses Beispiel an:

Wir haben zwei Zeilen in reminder mit dem gleichen start -Wert und die IDs 3 und 7:

%Vor%

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

%Vor%

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

sein %Vor%

oder

%Vor%

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

Fügen Sie einfach zuerst alle Zeilen ein.

%Vor%

Übereinstimmen / verbinden Sie zwei Tabellen in start Spalte mit dem Wissen, dass es nicht eindeutig ist. "Machen Sie es", indem Sie ROW_NUMBER hinzufügen und durch zwei Spalten verbinden. Es ist möglich, die Abfrage kürzer zu machen, aber ich habe jeden Schritt explizit formuliert:

%Vor%

Ich hoffe, es ist klar aus dem Code, was es tut, vor allem, wenn Sie es mit der einfacheren Version ohne ROW_NUMBER vergleichen. Offensichtlich funktioniert die komplexe Lösung auch dann, wenn start eindeutig ist, aber sie ist nicht so effizient wie eine einfache Lösung.

Diese Lösung setzt voraus, dass dateset vor diesem Prozess leer ist.

    
Vladimir Baranov 09.02.2015, 11:01
quelle
6

Hier ist eine andere Art, es zu tun, die sich von den drei Wegen unterscheidet, die Vladimir vorgeschlagen hat.

Mit einer temporären Funktion können Sie die ID der neu erstellten Zeilen sowie andere Werte in der Abfrage lesen:

%Vor%

Diese Herangehensweise an das Problem ergab sich, nachdem ich festgestellt hatte, dass das Schreiben von INSERT ... RETURNING als Unterabfrage das Problem lösen würde; Obwohl INSERT s als Unterabfragen nicht erlaubt sind, sind Aufrufe von Funktionen sicherlich.

Interessanterweise deutet dies darauf hin, dass DML-Unterabfragen, die Werte zurückgeben, sehr nützlich sein können. Wenn sie möglich wären, würden wir einfach schreiben:

%Vor%     
ellisbben 10.02.2015 06:37
quelle
4

Sie können Spalten nur mit RETURNING vom INSERT-Teil und nicht von der ausgewählten Tabelle zurückgeben. Also, wenn Sie bereit sind, eine Spalte reminder_id zu Ihrer Dateset-Tabelle hinzuzufügen,

%Vor%

Die folgende Anweisung funktioniert:

%Vor%

Nur wenn die Werte der Spalte start in Erinnerungen alle eindeutig sind , werden die folgenden beiden Anweisungen verwendet funktionieren auch:

%Vor%     
ralf.w. 09.02.2015 08:27
quelle
3

Das Problem besteht darin, dass Sie nur Spalten zurückgeben können, die in der Tabelle enthalten sind, in die Sie einfügen. Sie könnten es lösen, indem Sie dem Tabellen-Dataset eine zusätzliche Spalte geben, in die Sie reminder.id einfügen, damit Sie sie zurückgeben können.

Nach der Migration können Sie diese Spalte löschen.

    
Eelke 09.02.2015 08:05
quelle

Tags und Links