PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Używanie CASE w PostgreSQL do jednoczesnego wpływania na wiele kolumn

1. Standard-SQL:LEFT JOIN pojedynczy rząd wartości

Możesz LEFT JOIN wiersz wartości przy użyciu warunku (a tym samym jednokrotne obliczenie). Następnie możesz dodać wartości rezerwowe na kolumnę za pomocą COALESCE() .

Ten wariant składni jest krótszy i nieco szybszy z wieloma wartościami - szczególnie interesujący w przypadku drogiego/długiego stanu:

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;

Ponieważ tabela pochodna x składa się z singli wiersz, łączenie bez dalszych warunków jest w porządku.

Wyraźne rzuty typu są niezbędne w podzapytaniu. Używam text w przykładzie (co i tak jest domyślne dla literałów łańcuchowych). Użyj swoich rzeczywistych typów danych. Skrót składni value::type jest specyficzny dla Postgresa, użyj cast(value AS type) dla standardowego SQL.

Jeśli warunek nie jest TRUE , wszystkie wartości w x są NULL i COALESCE wskakuje.

Lub , ponieważ wszystkie wartości kandydujące pochodzą z tabeli rtd2 w Twoim konkretnym przypadku LEFT JOIN do rtd2 używając oryginalnego CASE warunek i CROSS JOIN do wiersza z wartościami domyślnymi:

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;

Zależy to od warunków przyłączenia i reszty zapytania.

2. Specyficzne dla PostgreSQL

2a. Rozwiń tablicę

Jeśli różne kolumny mają ten sam ten sam typ danych , możesz użyć tablicy w podzapytaniu i rozwinąć ją w zewnętrznym 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;

Sprawa się komplikuje, jeśli kolumny nie mają tego samego typu danych. Możesz przesłać je wszystkie do text (i opcjonalnie przekonwertuj z powrotem w zewnętrznym SELECT ) lub możesz ...

2b. Rozłóż typ wiersza

Możesz użyć niestandardowego typu złożonego (typu wiersza) do przechowywania wartości różnych typów i po prostu *-rozwiń go w zewnętrznym SELECT . Załóżmy, że mamy trzy kolumny:text , integer i date . Za powtarzane użyj, utwórz niestandardowy typ złożony:

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

Lub jeśli typ istniejącej tabeli pasuje, możesz po prostu użyć nazwy tabeli jako typu złożonego.

Lub jeśli potrzebujesz tylko typu tymczasowo , możesz utworzyć TEMPORARY TABLE , który rejestruje typ tymczasowy na czas trwania Twojej sesji :

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

Możesz to zrobić nawet w przypadku pojedynczej transakcji :

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

Następnie możesz użyć tego zapytania:

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;

Lub nawet po prostu (tak samo jak powyżej, prostsze, krótsze, może mniej zrozumiałe):

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 wyrażenie jest w ten sposób oceniane raz dla każdej kolumny. Jeśli ocena nie jest trywialna, inny wariant z podzapytaniem będzie szybszy.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak uruchomić serwer PostgreSQL w systemie Mac OS X przez Homebrew?

  2. czy pg_restore nadpisze istniejące tabele?

  3. Railsy resetują WSZYSTKIE sekwencje Postgresa?

  4. psycopg2 i nieskończony skrypt Pythona

  5. W jaki sposób search_path wpływa na rozpoznawanie identyfikatora i bieżący schemat?