sql >> Databasteknik >  >> RDS >> PostgreSQL

Använder CASE i PostgreSQL för att påverka flera kolumner samtidigt

1. Standard-SQL:LEFT JOIN en enda rad med värden

Du kan LEFT JOIN en rad med värden som använder villkoret (och utvärderar det en gång). Sedan kan du lägga till reservvärden per kolumn med COALESCE() .

Denna syntaxvariant är kortare och något snabbare med flera värden - speciellt intressant för ett dyrt/långt tillstånd:

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;

Eftersom den härledda tabellen x består av en singel rad, går det bra att gå med utan ytterligare villkor.

Explicita casts är nödvändiga i underfrågan. Jag använder text i exemplet (vilket är standard för strängliterals ändå). Använd dina faktiska datatyper. Syntaxgenvägen value::type är Postgres-specifik, använd cast(value AS type) för standard SQL.

Om villkoret inte är TRUE , alla värden i x är NULL och COALESCE slår in.

Eller , eftersom alla kandidatvärden kommer från tabellen rtd2 i ditt specifika fall, LEFT JOIN till rtd2 med den ursprungliga CASE condition och CROSS JOIN till en rad med standardvärden:

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;

Det beror på anslutningsvillkoren och resten av frågan.

2. PostgreSQL-specifik

2a. Expandera en array

Om dina olika kolumner delar samma datatyp , kan du använda en array i en underfråga och expandera den i den yttre SELECT :

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;

Det blir mer komplicerat om kolumnerna inte delar samma datatyp. Du kan antingen casta dem alla till text (och eventuellt konvertera tillbaka i den yttre SELECT ), eller så kan du ...

2b. Dekomponera en radtyp

Du kan använda en anpassad sammansatt typ (radtyp) för att hålla värden av olika typer och helt enkelt *-expandera den i den yttre SELECT . Säg att vi har tre kolumner:text , integer och date . För upprepade använd, skapa en anpassad sammansatt typ:

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

Eller om typen av en befintlig tabell matchar kan du bara använda tabellnamnet som sammansatt typ.

Eller om du bara behöver typen tillfälligt , kan du skapa en TEMPORARY TABLE , som registrerar en tillfällig typ under din session :

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

Du kan till och med göra detta för en enskild transaktion :

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

Sedan kan du använda den här frågan:

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;

Eller till och med bara (samma som ovan, enklare, kortare, kanske mindre lätt att förstå):

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

CASE uttryck utvärderas en gång för varje kolumn på detta sätt. Om utvärderingen inte är trivial blir den andra varianten med en underfråga snabbare.



  1. Lägga till flera textrutor i en mysql-databas

  2. Asynkron replikering automatisk failover i MySQL 8.0.22

  3. Bulk Infoga i Oracle-databas:Vilket är bättre:FÖR Cursor loop eller en enkel Select?

  4. Hur exporterar man analyserad data från Python till en Oracle-tabell i SQL Developer?