PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Usando CASE no PostgreSQL para afetar várias colunas de uma só vez

1. SQL padrão:LEFT JOIN uma única linha de valores


Você pode LEFT JOIN uma linha de valores usando a condição (avaliando-a assim uma vez). Em seguida, você pode adicionar valores de fallback por coluna com COALESCE() .

Essa variante de sintaxe é mais curta e um pouco mais rápida com vários valores - especialmente interessante para uma condição cara/longa:
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;

Como a tabela derivada x consiste em um único linha, juntar sem mais condições está bem.

Lançamentos de tipo explícito são necessários na subconsulta. Eu uso text no exemplo (que é o padrão para literais de string de qualquer maneira). Use seus tipos de dados reais. O atalho de sintaxe value::type é específico do Postgres, use cast(value AS type) para SQL padrão.

Se a condição não for TRUE , todos os valores em x são NULL e COALESCE entra em ação.

Ou , já que todos os valores candidatos vêm da tabela rtd2 no seu caso particular, LEFT JOIN para rtd2 usando o CASE original condição e CROSS JOIN para uma linha com valores padrão:
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;

Depende das condições de junção e do restante da consulta.

2. Específico do PostgreSQL

2a. Expandir uma matriz


Se suas várias colunas compartilharem o mesmo tipo de dados , você pode usar uma matriz em uma subconsulta e expandi-la no SELECT externo :
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;

Fica mais complicado se as colunas não compartilharem o mesmo tipo de dados. Você pode convertê-los todos para text (e opcionalmente converter de volta no SELECT externo ), ou você pode ...

2b. Decompor um tipo de linha


Você pode usar um tipo composto personalizado (tipo de linha) para armazenar valores de vários tipos e simplesmente *-expandê-lo no SELECT externo . Digamos que temos três colunas:text , integer e date . Para repetidos use, crie um tipo composto personalizado:
CREATE TYPE my_type (t1 text, t2 int, t3 date);

Ou se o tipo de uma tabela existente corresponder, você pode simplesmente usar o nome da tabela como tipo composto.

Ou se você precisar apenas do tipo temporariamente , você pode criar uma TEMPORARY TABLE , que registra um tipo temporário para a duração de sua sessão :
CREATE TEMP TABLE my_type (t1 text, t2 int, t3 date);

Você pode até fazer isso para uma transação única :
CREATE TEMP TABLE my_type (t1 text, t2 int, t3 date) ON COMMIT DROP;

Então você pode usar esta consulta:
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;

Ou mesmo apenas (o mesmo que acima, mais simples, mais curto, talvez menos fácil de entender):
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>;

O CASE expressão é avaliada uma vez para cada coluna desta forma. Se a avaliação não for trivial, a outra variante com uma subconsulta será mais rápida.