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

Utilizzo di CASE in PostgreSQL per influenzare più colonne contemporaneamente

1. Standard-SQL:LEFT JOIN una singola riga di valori

Potresti LEFT JOIN una riga di valori che utilizza la condizione (valutandola quindi una volta). Quindi puoi aggiungere valori di fallback per colonna con COALESCE() .

Questa variante della sintassi è più breve e leggermente più veloce con valori multipli, particolarmente interessante per una condizione costosa/lunga:

SELECT COALESCE(x.txt1, trim(r2.team_name))     AS testing_testing
     , COALESCE(x.txt2, trim(r2.normal_data))   AS test_response
     , COALESCE(x.txt3, trim(r2.normal_data_2)) AS another_example
FROM   rtp
JOIN   rtd2 r2 ON <unknown condition> -- missing context in question
LEFT   JOIN (
   SELECT 'testing'::text         AS txt1
        , 'test example'::text    AS txt2
        , 'test example #2'::text AS txt3
   ) x ON rtp.team_id = rtp.sub_team_id;

Poiché la tabella derivata x consiste in un singolo fila, l'adesione senza ulteriori condizioni va bene.

Cast di tipo esplicito sono necessari nella sottoquery. Uso text nell'esempio (che è comunque l'impostazione predefinita per le stringhe letterali). Usa i tuoi tipi di dati effettivi. La scorciatoia sintattica value::type è specifico di Postgres, usa cast(value AS type) per SQL standard.

Se la condizione non è TRUE , tutti i valori in x sono NULL e COALESCE entra in gioco.

Oppure , poiché tutti i valori candidati provengono dalla tabella rtd2 nel tuo caso particolare, LEFT JOIN a rtd2 utilizzando il CASE originale condizione e CROSS JOIN in una riga con valori predefiniti:

SELECT COALESCE(trim(r2.team_name),     x.txt1) AS testing_testing
     , COALESCE(trim(r2.normal_data),   x.txt2) AS test_response
     , COALESCE(trim(r2.normal_data_2), x.txt3) AS another_example
FROM   rtp
LEFT   JOIN rtd2 r2 ON <unknown condition>  -- missing context in question
                   AND rtp.team_id = rtp.sub_team_id
CROSS  JOIN (
   SELECT 'testing'::text         AS txt1
        , 'test example'::text    AS txt2
        , 'test example #2'::text AS txt3
   ) x;

Dipende dalle condizioni di unione e dal resto della query.

2. Specifico per PostgreSQL

2a. Espandi una matrice

Se le varie colonne condividono lo stesso tipo di dati , puoi utilizzare un array in una sottoquery ed espanderlo nel SELECT esterno :

SELECT x.combo[1], x.combo[2], x.combo[3]
FROM  (
   SELECT CASE WHEN rtp.team_id = rtp.sub_team_id
            THEN '{test1,test2,test3}'::text[]
            ELSE ARRAY[trim(r2.team_name)
                     , trim(r2.normal_data)
                     , trim(r2.normal_data_2)]
          END AS combo
   FROM   rtp
   JOIN   rtd2 r2 ON <unknown condition>
   ) x;

Diventa più complicato se le colonne non condividono lo stesso tipo di dati. Puoi trasmetterli tutti a text (e facoltativamente riconvertire nel SELECT esterno ), oppure puoi...

2b. Scomponi un tipo di riga

Puoi utilizzare un tipo composito personalizzato (tipo riga) per contenere valori di vari tipi e semplicemente *-espandilo nel SELECT esterno . Supponiamo di avere tre colonne:text , integer e date . Per ripetuto utilizzare, creare un tipo composito personalizzato:

CREATE TYPE my_type (t1 text, t2 int, t3 date);

Oppure se il tipo di una tabella esistente corrisponde, puoi semplicemente utilizzare il nome della tabella come tipo composto.

Oppure se ti serve solo il tipo temporaneamente , puoi creare una TEMPORARY TABLE , che registra un tipo temporaneo per la durata della tua sessione :

CREATE TEMP TABLE my_type (t1 text, t2 int, t3 date);

Potresti anche farlo per una singola transazione :

CREATE TEMP TABLE my_type (t1 text, t2 int, t3 date) ON COMMIT DROP;

Quindi puoi utilizzare questa query:

SELECT (x.combo).*  -- parenthesis required
FROM  (
   SELECT CASE WHEN rtp.team_id = rtp.sub_team_id
             THEN ('test', 3, now()::date)::my_type  -- example values
             ELSE (r2.team_name
                 , r2.int_col
                 , r2.date_col)::my_type
          END AS combo
   FROM   rtp
   JOIN   rtd2 r2 ON <unknown condition>
   ) x;

O anche solo (come sopra, più semplice, più breve, forse meno facile da capire):

SELECT (CASE WHEN rtp.team_id = rtp.sub_team_id
           THEN ('test', 3, now()::date)::my_type
           ELSE (r2.team_name, r2.int_col, r2.date_col)::my_type
        END).*
FROM   rtp
JOIN   rtd2 r2 ON <unknown condition>;

Il CASE espressione viene valutata una volta per ogni colonna in questo modo. Se la valutazione non è banale, l'altra variante con una sottoquery sarà più veloce.