Postgres的模拟交叉适用于SQL服务器(Postgres analogue to CROSS

2019-06-17 11:24发布

我需要迁移的MS SQL Server 2005的写入的Postgres 9.1的SQL查询。
什么是替代的最佳方式CROSS APPLY在此查询?

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

GetCitizenRecModified()函数是一个表值函数。 我不能把这个函数的代码,因为它确实是巨大的,它使一些难以计算的,我不能放弃它。

Answer 1:

在Postgres的9.3或更高版本使用LATERAL联接:

SELECT v.col_a, v.col_b, f.*  -- no parentheses here, 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 TABLERETURNS SETOF recordRETURNS 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) AS
$func$
SELECT s.col_c, s.col_d
FROM   some_tbl s
WHERE  s.col_a = $1
AND    s.col_b = $2
$func$ LANGUAGE sql;

你需要,如果你想申请一个来包装这个在子查询或CTE WHERE因为列不是在同一水平上可见的条款。 (和它的性能更好,无论如何,因为你防止反复评估函数的每个输出列):

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;

还有其他几种方法可以做到这一点或类似的东西。 这一切都取决于你想要什么。



Answer 2:

Necromancing:
在新的PostgreSQL 9.3:

横向关键字

左| 右| INNER JOIN 侧向

INNER JOIN LATERAL是一样的CROSS APPLY
LEFT JOIN LATERAL相同OUTER APPLY

实例:

SELECT * FROM T_Contacts 

--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1 
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989


LEFT JOIN LATERAL 
(
    SELECT 
         --MAP_CTCOU_UID    
         MAP_CTCOU_CT_UID   
        ,MAP_CTCOU_COU_UID  
        ,MAP_CTCOU_DateFrom 
        ,MAP_CTCOU_DateTo   
   FROM T_MAP_Contacts_Ref_OrganisationalUnit 
   WHERE MAP_CTCOU_SoftDeleteStatus = 1 
   AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID 

    /*  
    AND 
    ( 
        (__in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo) 
        AND 
        (__in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom) 
    ) 
    */
   ORDER BY MAP_CTCOU_DateFrom 
   LIMIT 1 
) AS FirstOE 


Answer 3:

我喜欢欧文Brandstetter修改的答案然而,我发现性能问题:运行时,

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

该f_citizen_rec_modified功能将被跑1次,每次返回列(在v_citizenversions乘以每一行)。 我没有找到这种效应的文件,但可以通过调试来推断它。 现在的问题是,我们如何能(9.3哪里横向连接可用之前),而这样的表现抢劫副作用得到这样的效果呢?

更新:我似乎已经找到了答案。 重写查询,如下所示:

select x.col1, x.col2, x.col3, (x.func).* 
FROM (select SELECT v.col1, v.col2, v.col3, f_citizen_rec_modified(col1, col2) func
FROM   v_citizenversions v) x

那么关键差别是第一获取的原始功能的结果(内子查询)包裹,在另一选择半身像这些结果伸到列。 这是对PG 9.2测试



Answer 4:

此链接似乎显示如何做到这一点了在Postgres 9.0或更高版本:

PostgreSQL的:参数化递归CTE

它进一步的向下一节中的页面“仿真进CROSS APPLY与集返回功能”。 请务必在示例后要注意限制列表。



文章来源: Postgres analogue to CROSS APPLY in SQL Server