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

Wählen Sie Zeilenzellen als neue Spalten aus

Diese Frage war viel schwieriger zu lösen, als Sie vielleicht erwartet haben. Ihr Versuch mit crosstab() zielte in die richtige Richtung. Aber um dynamische Spaltennamen zu vergeben, benötigen Sie zusätzlich dynamisches SQL:EXECUTE in einer plpgsql-Funktion.

Ändern Sie den Datentyp der Spalte infos.type aus text zu regtype um SQL-Injection und andere Fehler zu verhindern. Sie haben zum Beispiel den Datentyp number , was kein gültiger PostgreSQL-Datentyp ist. Ich habe es durch numeric ersetzt , damit es funktionieren kann.

Sie könnten Vereinfachen Sie die Aufgabe, indem Sie Spaltennamen vermeiden, die doppelte Anführungszeichen erfordern. Wie nume_anterior statt "nume anterior" .

Vielleicht möchten Sie eine Spalte row_id hinzufügen zu Ihrer Tabelle info_data um alle Elemente einer Zeile zu markieren. Sie benötigen es für die crosstab() -Funktion und erlaubt Ihnen, Spalten mit NULL zu ignorieren Werte. Die crosstab() Funktion mit zwei Parametern kann mit fehlenden Spalten umgehen. Ich synthetisiere die fehlende Spalte mit dem Ausdruck (d.id-1)/13 unten - was für die Daten in Ihrem Beispiel funktioniert.

Sie müssen das Zusatzmodul tablefunc installieren (einmal pro Datenbank):

CREATE EXTENSION tablefunc;

zusätzliche Erläuterungen und Links in dieser zugehörigen Antwort .

Diese Funktion wird das tun, wonach gesucht wird:

CREATE OR REPLACE FUNCTION f_mytbl()
  RETURNS TABLE (id int
, nume text           , prenume text       , cnp numeric
, "nume anterior" text, "stare civila" text, cetatenie text
, rezidenta text      , adresa text        , "tip act" text
, "serie ci" text     , "numar ci" text    , "data eliberarii" text
, "eliberat de" text)
  LANGUAGE plpgsql AS
$BODY$
BEGIN

RETURN QUERY EXECUTE $f$
SELECT *
FROM   crosstab(
    'SELECT (d.id-1)/13 -- AS row_id
          , i.id, d.value
     FROM   infos i
     JOIN   info_data d ON d.id_info = i.id
     ORDER  BY 1, i.id',

    'SELECT id
     FROM   infos
     ORDER  BY id'
    )
AS tbl ($f$ || 'id int,
, nume text           , prenume text       , cnp numeric
, "nume anterior" text, "stare civila" text, cetatenie text
, rezidenta text      , adresa text        , "tip act" text
, "serie ci" text     , "numar ci" text    , "data eliberarii" text
, "eliberat de" text)';

END;
$BODY$;

Aufruf:

SELECT * FROM x.mytbl();

Lassen Sie sich nicht durch die verschachtelten Dollar-Notierung .

Übrigens:Ich habe die Spaltenliste mit dieser Anweisung erstellt:

SELECT 'id int,' || string_agg(quote_ident(name) || ' ' || type
                              ,', ' ORDER BY i.id) 
FROM   infos i;