sql - Postgres 类似于 SQL Server 中的 CROSS APPLY

标签 sql postgresql postgresql-9.1 cross-apply lateral

我需要将为 MS SQL Server 2005 编写的 SQL 查询迁移到 Postgres 9.1。
在此查询中替代 CROSS APPLY 的最佳方法是什么?

SELECT *
FROM V_CitizenVersions         
CROSS APPLY     
       dbo.GetCitizenRecModified(Citizen, LastName, FirstName, MiddleName,
BirthYear, BirthMonth, BirthDay, ..... ) -- lots of params

GetCitizenRecModified() 函数是一个表值函数。我无法放置此函数的代码,因为它实在是太大了,它会造成一些困难的计算,我不能放弃它。

最佳答案

在 Postgres 9.3 或更高版本中使用 LATERAL 连接:

SELECT v.col_a, v.col_b, f.*  -- no parentheses, f is a table alias
FROM   v_citizenversions v
LEFT   JOIN LATERAL f_citizen_rec_modified(v.col1, v.col2) f ON true
WHERE  f.col_c = _col_c;

为什么 LEFT JOIN LATERAL ... ON true


对于旧版本,有一种非常简单的方法可以我认为您尝试使用设置返回函数 ( RETURNS TABLE or RETURNS SETOF record OR RETURNS record ) 来完成:

SELECT *, (f_citizen_rec_modified(col1, col2)).*
FROM   v_citizenversions v

该函数为外部查询的每一行计算一次值。如果该函数返回多行,则结果行将相应地相乘。所有括号在句法上都是必需的 以分解行类型。表函数可能看起来像这样:

CREATE OR REPLACE FUNCTION f_citizen_rec_modified(_col1 int, _col2 text)
  RETURNS TABLE(col_c integer, col_d text)
  LANGUAGE sql AS
$func$
SELECT s.col_c, s.col_d
FROM   some_tbl s
WHERE  s.col_a = $1
AND    s.col_b = $2
$func$;

如果要应用 WHERE 子句,则需要将其包装在子查询或 CTE 中,因为列在同一级别上不可见。 (无论如何,它对性能更好,因为您防止对函数的每个输出列进行重复计算):

SELECT col_a, col_b, (f_row).*
FROM  (
   SELECT col_a, col_b, f_citizen_rec_modified(col1, col2) AS f_row
   FROM   v_citizenversions v
   ) x
WHERE (f_row).col_c = _col_c;

还有其他几种方法可以做到这一点或类似的事情。这完全取决于您到底想要什么。

关于sql - Postgres 类似于 SQL Server 中的 CROSS APPLY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11472790/

相关文章:

SQL 外键数组引用非数组

sql - 从仅记录值更改时的表中推断每日历史值 (Postgresql 9.3)

postgresql - 对复杂jsonb内容进行全文检索

scala - 使用 JDBC 创建 PostgreSQL 触发器

sql - 数据库设计 : should nested objects have their own table?

mysql - 在 MySQL 中用连接替换子查询

mysql - 计算特定行 ID 的 NOT NULL 列数(查询)

mysql - 根据多列选择最大值列行

sql - 如何对用户进行排名并从该排名中获取我的用户以及按排名位置高于和低于用户的子集

sql - 控制到达功能结束而没有 RETURN