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

Verwenden von CASE in PostgreSQL, um mehrere Spalten gleichzeitig zu beeinflussen

1. Standard-SQL:LEFT JOIN eine einzelne Reihe von Werten

Sie könnten LEFT JOIN eine Reihe von Werten, die die Bedingung verwenden (wodurch sie einmal ausgewertet wird). Dann können Sie Fallback-Werte pro Spalte mit hinzufügen COALESCE() .

Diese Syntaxvariante ist kürzer und bei mehreren Werten etwas schneller - besonders interessant für eine teure / langwierige Bedingung:

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;

Da die abgeleitete Tabelle x besteht aus einer einzelnen Zeile, Beitritt ohne weitere Bedingungen ist in Ordnung.

Explizite Typumwandlungen sind in der Unterabfrage erforderlich. Ich verwende text im Beispiel (was sowieso der Standard für String-Literale ist). Verwenden Sie Ihre tatsächlichen Datentypen. Die Syntaxverknüpfung value::type Postgres-spezifisch ist, verwenden Sie cast(value AS type) für Standard-SQL.

Wenn die Bedingung nicht TRUE ist , alle Werte in x sind NULL und COALESCE tritt ein.

Oder , da alle Kandidatenwerte aus der Tabelle rtd2 stammen in Ihrem speziellen Fall LEFT JOIN zu rtd2 unter Verwendung des ursprünglichen CASE Bedingung und CROSS JOIN zu einer Zeile mit Standardwerten:

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;

Dies hängt von den Join-Bedingungen und dem Rest der Abfrage ab.

2. PostgreSQL-spezifisch

2a. Erweitern Sie ein Array

Wenn Ihre verschiedenen Spalten den gleichen Datentyp gemeinsam haben , können Sie ein Array in einer Unterabfrage verwenden und es im äußeren SELECT erweitern :

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;

Komplizierter wird es, wenn die Spalten nicht den gleichen Datentyp haben. Sie können sie entweder alle in text umwandeln (und optional im äußeren SELECT zurückwandeln ), oder Sie können ...

2b. Einen Zeilentyp zerlegen

Sie können einen benutzerdefinierten zusammengesetzten Typ (Zeilentyp) verwenden, um Werte verschiedener Typen aufzunehmen, und ihn einfach im äußeren SELECT mit * erweitern . Angenommen, wir haben drei Spalten:text , integer und date . Für wiederholt verwenden, erstellen Sie einen benutzerdefinierten zusammengesetzten Typ:

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

Oder Wenn der Typ einer vorhandenen Tabelle übereinstimmt, können Sie einfach den Tabellennamen als zusammengesetzten Typ verwenden.

Oder wenn Sie den Typ nur vorübergehend benötigen , können Sie eine TEMPORARY TABLE erstellen , das einen temporären Typ für die Dauer Ihrer Sitzung registriert :

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

Sie könnten dies sogar für eine einzelne Transaktion tun :

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

Dann können Sie diese Abfrage verwenden:

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;

Oder auch nur (wie oben, einfacher, kürzer, vielleicht weniger leicht verständlich):

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

Der CASE Ausdruck wird auf diese Weise einmal für jede Spalte ausgewertet. Ist die Auswertung nicht trivial, ist die andere Variante mit Unterabfrage schneller.