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

Podziel rekord zwrócony przez funkcję na wiele kolumn

W Postgresie 9.3 lub później najlepiej to rozwiązać za pomocą LATERAL dołącz:

SELECT *
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

Pozwala uniknąć powtórnej oceny funkcji (dla każdej kolumny w danych wyjściowych — funkcja musi być wywoływana dla każdego wiersza wejściowego i tak).
LEFT JOIN LATERAL ... ON true aby uniknąć upuszczania wierszy z lewej strony, jeśli funkcja nie zwraca żadnego wiersza:

  • Jaka jest różnica między LATERAL a podzapytanie w PostgreSQL?

Kontynuacja w Twoim komentarzu:

tylko rozszerzone kolumny utworzone przez wywołanie funkcji

SELECT x.*  -- that's all!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

Ale ponieważ nie interesują Cię inne kolumny, możesz uprościć:

SELECT x.*
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
     , hi_lo(a.actor_id, length(a.name), ma.movie_id) x
LIMIT  10;

Który jest niejawnym CROSS JOIN LATERAL . Jeśli funkcja może czasami zwracać "brak wiersza", wynik może być inny:nie otrzymujemy wartości NULL dla wierszy, wiersze te są po prostu eliminowane - i LIMIT już ich nie liczy.

W starszych wersjach (lub ogólnie) możesz też po prostu rozłożyć typ złożony z odpowiednią składnią:

SELECT *, (hi_lo(a.actor_id, length(a.name), ma.movie_id)).*  -- note extra parentheses!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LIMIT  10;

Wadą jest to, że funkcja jest oceniana raz dla każdej kolumny w wynikach funkcji ze względu na słabość planera zapytań Postgres. Lepiej przenieść wywołanie do podzapytania lub CTE i zdekomponować typ wiersza w zewnętrznym SELECT . Na przykład:

SELECT actor_id, movie_id, (x).*  -- explicit column names for the rest
FROM  (
   SELECT *, hi_lo(a.actor_id, length(a.name), ma.movie_id) AS x
   FROM   actors a 
   JOIN   movies_actors ma on a.actor_id = ma.movie_id 
   LIMIT  10
   ) sub;

Ale musisz nazwać poszczególne kolumny i nie możesz uciec z SELECT * chyba że nie masz nic przeciwko zbędnemu typowi wiersza w wyniku.Powiązane:

  • Unikaj wielu wywołań tej samej funkcji podczas rozwijania wyniku złożonego
  • Jak uniknąć wielu ewaluacji funkcji za pomocą składni (func()).* w zapytaniu SQL?



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ściągawka konfiguracji PostgreSQL

  2. Jak zmapować pole tablicy PostgreSQL w Django ORM?

  3. Przewodnik po partycjonowaniu danych w PostgreSQL

  4. Postgresql DROP TABLE nie działa

  5. Uruchamianie i zapełnianie kontenera Postgres w Docker