В Postgres 9.3 или по-късно това се решава най-добре с LATERAL
присъединете се:
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;
Избягва многократно оценяване на функцията (за всяка колона в изхода - функцията трябва да бъде извикана за всеки входен ред така или иначе).LEFT JOIN LATERAL ... ON true
за да избегнете изпускането на редове от лявата страна, ако функцията не върне ред:
- Каква е разликата между LATERAL и подзаявка в PostgreSQL?
Продължение във вашия коментар:
само разширените колони, произведени от извикването на функция
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;
Но тъй като не ви пука за други колони, можете да опростите до:
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;
Което е имплицитно CROSS JOIN LATERAL
. Ако функцията може действително да връща "no row" от време на време, резултатът може да бъде различен:ние не получаваме NULL стойности за редовете, тези редове просто се елиминират - и LIMIT
не ги брои повече.
Впо-стари версии (или като цяло) можете също да разложите съставния тип с правилния синтаксис:
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;
Недостатъкът е, че функцията се оценява веднъж за всяка колона в изхода на функцията поради слабост в планера на заявки на Postgres. По-добре е да преместите повикването в подзаявка или CTE и да разложите типа на реда във външния SELECT
. Като:
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;
Но трябва да наименувате отделни колони и не можете да се разминете с SELECT *
освен ако не сте наред с вида на реда в резултата излишно. Свързано:
- Избягвайте множество извиквания на една и съща функция, когато разширявате съставния резултат
- Как да избегнем множество функции eval със синтаксиса (func()).* в SQL заявка?