sql >> Base de Datos >  >> RDS >> PostgreSQL

Uso de CASE en PostgreSQL para afectar varias columnas a la vez

1. SQL estándar:LEFT JOIN una sola fila de valores

Podrías LEFT JOIN una fila de valores usando la condición (evaluándola así una vez). Luego puede agregar valores alternativos por columna con COALESCE() .

Esta variante de sintaxis es más corta y un poco más rápida con múltiples valores, especialmente interesante para una condición costosa/larga:

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;

Dado que la tabla derivada x consiste en un simple fila, unirse sin más condiciones está bien.

Conversiones de tipos explícitos son necesarios en la subconsulta. Yo uso text en el ejemplo (que es el valor predeterminado para los literales de cadena de todos modos). Utilice sus tipos de datos reales. El atajo de sintaxis value::type es específico de Postgres, use cast(value AS type) para SQL estándar.

Si la condición no es TRUE , todos los valores en x son NULL y COALESCE entra en acción.

O , ya que todos los valores candidatos provienen de la tabla rtd2 en su caso particular, LEFT JOIN a rtd2 usando el CASE original condición y CROSS JOIN a una fila con valores predeterminados:

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 de las condiciones de unión y del resto de la consulta.

2. Específico de PostgreSQL

2a. Expandir una matriz

Si sus diversas columnas comparten el mismo tipo de datos , puede usar una matriz en una subconsulta y expandirla en el 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;

Se vuelve más complicado si las columnas no comparten el mismo tipo de datos. Puedes convertirlos todos en text (y, opcionalmente, volver a convertir en el exterior SELECT ), o puede...

2b. Descomponer un tipo de fila

Puede usar un tipo compuesto personalizado (tipo de fila) para contener valores de varios tipos y simplemente *-expándalo en el exterior SELECT . Digamos que tenemos tres columnas:text , integer y date . Para repetidas use, cree un tipo compuesto personalizado:

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

O si el tipo de una tabla existente coincide, puede usar el nombre de la tabla como tipo compuesto.

O si solo necesita el tipo temporalmente , puede crear una TEMPORARY TABLE , que registra un tipo temporal durante la duración de su sesión :

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

Incluso podría hacer esto para una transacción única :

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

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

O simplemente (igual que arriba, más simple, más corto, tal vez 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>;

El CASE expresión se evalúa una vez para cada columna de esta manera. Si la evaluación no es trivial, la otra variante con una subconsulta será más rápida.