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

Seleziona le celle di riga come nuove colonne

Questa domanda era molto più difficile da risolvere di quanto potresti aspettarti. Il tuo tentativo con crosstab() mirava nella giusta direzione. Ma per assegnare nomi di colonna dinamici è necessario anche SQL dinamico:EXECUTE in una funzione plpgsql.

Modifica il tipo di dati della colonna infos.type da text a regtype per prevenire SQL injection e altri errori. Ad esempio, hai il tipo di dati number , che non è un tipo di dati PostgreSQL valido. L'ho sostituito con numeric , quindi può funzionare.

Potresti semplificare l'attività evitando i nomi di colonna che necessitano di virgolette doppie. Come nume_anterior invece di "nume anterior" .

Potresti voler aggiungere una colonna row_id alla tua tabella info_data per contrassegnare tutti gli elementi di una riga. Ne hai bisogno per il crosstab() e ti permette di ignorare le colonne con NULL i valori. La crosstab() la funzione con due parametri può gestire le colonne mancanti. Sintetizzo la colonna mancante con l'espressione (d.id-1)/13 sotto - che funziona per i dati nel tuo esempio.

È necessario installare il modulo aggiuntivo tablefunc (una volta per database):

CREATE EXTENSION tablefunc;

Trova ulteriori spiegazioni e link in questa risposta correlata .

Questa funzione farà ciò che stai cercando:

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$;

Chiama:

SELECT * FROM x.mytbl();

Non lasciarti confondere dal citazione del dollaro .

A proposito:ho creato l'elenco delle colonne con questa affermazione:

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