2012-07-13 100 views
12

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

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

GetCitizenRecModified()函数是一个表值函数。我不能放置这个函数的代码,因为它真的很庞大,它会产生一些困难的计算,我不能放弃它。

+0

你不需要跨在Postgres的适用。您可以像使用函数一样使用表函数。只需加入他们。 – 2012-07-13 15:36:11

+0

@a_horse_with_no_name - 'CROSS APPLY'用相关的参数重新执行TVF,而不是执行一次,然后加入结果。 – 2012-07-13 15:37:39

回答

8

在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 TABLE or RETURNS SETOF record OR RETURNS record一个非常简单的方法:

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

函数计算值o nce用于外部查询的每一行。如果该函数返回多行,则结果行将相应地相乘。所有括号在语法上都需要来分解行类型。表函数可以是这个样子:

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; 

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

+0

我用你提出的查询。现在我感到震惊:查询执行超过一分钟。在MS SQL中,它需要不到一秒的O_O。 – user1178399 2012-07-13 16:26:11

+1

@ user1178399:如果不知道游戏中的诸多因素,对它进行评论几乎是不可能的。我会推测性能可以提高。 – 2012-07-13 16:36:57

1

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

PostgreSQL: parameterizing a recursive CTE

它进一步下跌的页面标题为“仿真进CROSS与集返回功能APPLY”一节。请确保在示例后注明限制列表。

1

我喜欢欧文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

9

Necromancing:
在新的PostgreSQL 9.3:

侧向关键字

离开| right | 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