Wie würde ich bei zwei Tabellen mit einer undefinierten Zeilenanzahl mit einem Namen und einem Wert eine Pivot- CROSS JOIN
Funktion über ihren Werten anzeigen?
CREATE TEMP TABLE foo AS
SELECT x::text AS name, x::int
FROM generate_series(1,10) AS t(x);
CREATE TEMP TABLE bar AS
SELECT x::text AS name, x::int
FROM generate_series(1,5) AS t(x);
Wenn diese Funktion beispielsweise Multiplikation wäre, wie würde ich eine (Multiplikations-) Tabelle wie die folgende erzeugen?
Alle diese (arg1,arg2,result)
Zeilen können mit erzeugt werden
SELECT foo.name AS arg1, bar.name AS arg2, foo.x*bar.x AS result
FROM foo
CROSS JOIN bar;
Dies ist also nur eine Frage der Präsentation. Ich möchte, dass dies auch mit einem benutzerdefinierten Namen funktioniert - einem Namen, der nicht nur als Textargument dient CAST
, sondern in der Tabelle festgelegt ist.
CREATE TEMP TABLE foo AS
SELECT chr(x+64) AS name, x::int
FROM generate_series(1,10) AS t(x);
CREATE TEMP TABLE bar AS
SELECT chr(x+72) AS name, x::int
FROM generate_series(1,5) AS t(x);
Ich denke, dass dies mit einem CROSSTAB, der einen dynamischen Rückgabetyp aufweist, leicht möglich wäre.
SELECT * FROM crosstab(
'
SELECT foo.x AS arg1, bar.x AS arg2, foo.x*bar.x
FROM foo
CROSS JOIN bar
', 'SELECT DISTINCT name FROM bar'
) AS **MAGIC**
Aber ohne das **MAGIC**
bekomme ich
ERROR: a column definition list is required for functions returning "record" LINE 1: SELECT * FROM crosstab(
Als Referenz der obigen Beispiele mit Namen verwenden , ist dies etwas mehr wie das, was tablefunc
‚s crosstab()
will.
SELECT * FROM crosstab(
'
SELECT foo.x AS arg1, bar.x AS arg2, foo.x*bar.x
FROM foo
CROSS JOIN bar
'
) AS t(row int, i int, j int, k int, l int, m int);
Aber jetzt kehren wir zu den Annahmen über den Inhalt und die Größe der bar
Tabelle in unserem Beispiel zurück. Also wenn,
- Die Tabellen sind undefiniert lang,
- Dann repräsentiert der Cross-Join einen Würfel mit undefinierter Dimension (wegen oben),
- Die Kategorienamen (Kreuzworträtsel) sind in der Tabelle aufgeführt
Was ist das Beste, was wir in PostgreSQL ohne eine "Spaltendefinitionsliste" tun können, um eine solche Präsentation zu erstellen?
quelle
Antworten:
Einfacher Fall, statisches SQL
Die nicht dynamische Lösung
crosstab()
für den einfachen Fall:Ich ordne die resultierenden Spalten nach
foo.name
, nicht nachfoo.x
. Beide werden zufällig parallel sortiert, aber das ist nur die einfache Einrichtung. Wählen Sie die richtige Sortierreihenfolge für Ihren Fall. Der tatsächliche Wert der zweiten Spalte ist in dieser Abfrage irrelevant (1-Parameter-Form voncrosstab()
).Wir brauchen nicht einmal
crosstab()
2 Parameter, da per Definition keine Werte fehlen. Sehen:(Sie haben die Kreuztabellenabfrage in der Frage durch Ersetzen
foo
durchbar
in einer späteren Bearbeitung behoben . Dadurch wird auch die Abfrage behoben , es wird jedoch weiterhin mit Namen von gearbeitetfoo
.)Unbekannter Rückgabetyp, dynamisches SQL
Spaltennamen und -typen können nicht dynamisch sein. SQL fordert zum Zeitpunkt des Aufrufs die Kenntnis von Nummer, Namen und Typen der resultierenden Spalten. Entweder durch explizite Deklaration oder anhand von Informationen in den Systemkatalogen (Das passiert mit
SELECT * FROM tbl
: Postgres schlägt die registrierte Tabellendefinition nach.)Sie möchten, dass Postgres resultierende Spalten aus Daten in einer Benutzertabelle ableitet. Das wird nicht passieren.
Auf die eine oder andere Weise benötigen Sie zwei Roundtrips zum Server. Entweder Sie erstellen einen Cursor und gehen dann durch. Oder Sie erstellen eine temporäre Tabelle und wählen sie aus. Oder Sie registrieren einen Typ und verwenden ihn im Anruf.
Oder Sie generieren die Abfrage einfach in einem Schritt und führen sie im nächsten aus:
Dadurch wird die obige Abfrage dynamisch generiert. Führen Sie es im nächsten Schritt aus.
Ich verwende Dollar-Anführungszeichen (
$$
), um die Handhabung verschachtelter Anführungszeichen einfach zu halten. Sehen:quote_ident()
ist wichtig, um ansonsten unzulässigen Spaltennamen zu entgehen (und möglicherweise gegen SQL-Injection zu verteidigen).Verbunden:
quelle
Wenn Sie dies als Präsentationsproblem einrahmen, können Sie eine Präsentationsfunktion nach der Abfrage in Betracht ziehen.
Neuere Versionen von
psql
(9.6) werden mit\crosstabview
einem Ergebnis in Kreuztabellendarstellung ohne SQL-Unterstützung geliefert (da SQL dies nicht direkt erzeugen kann, wie in @ Erwins Antwort erwähnt: SQL verlangt, dass Anzahl, Namen und Typen der resultierenden Spalten zum Aufrufzeitpunkt bekannt sind )Ihre erste Abfrage lautet beispielsweise:
Das zweite Beispiel mit ASCII-Spaltennamen lautet:
Weitere Informationen finden Sie im psql-Handbuch und unter https://wiki.postgresql.org/wiki/Crosstabview .
quelle
Dies ist keine endgültige Lösung
Das ist mein bisher bester Ansatz. Müssen noch das endgültige Array in Spalten konvertieren.
Zuerst habe ich das kartesische Produkt beider Tabellen:
Ich habe jedoch eine Zeilennummer hinzugefügt, um jede Zeile der ersten Tabelle zu identifizieren.
Dann habe ich das Ergebnis in diesem Format erstellt:
Konvertieren in einen durch Kommas getrennten String:
(Nur um es später zu versuchen: http://rextester.com/NBCYXA2183 )
quelle
Nebenbei bemerkt scheint SQL: 2016 dies mit polymorphen Tabellenfunktionen zu berücksichtigen (ISO / IEC TR 19075-7: 2017).
Ich habe den Link Was ist neu in SQL: 2016 gefunden, aber der Autor geht nicht weiter darauf ein.
quelle