在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 trueLIMIT 10;
避免重复评估函数(对于输出中的每一列-必须以任何一种方式为每个输入行调用该函数)。
LEFT JOIN LATERAL ... ON true如果函数不返回行,则避免从左侧删除行
在您的评论中进行跟进:
仅由函数调用产生的扩展列
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 trueLIMIT 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) xLIMIT 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 restFROM ( 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 *除非您对结果中的行类型有多余的理解,否则您将无法避免。



