簡體   English   中英

Postgres模擬與SQL Server中的交叉應用

[英]Postgres analogue to CROSS APPLY in SQL Server

我需要將為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 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;

如果要應用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;

還有其他幾種方法可以執行此操作或執行類似操作。 這完全取決於您想要什么。

死靈法師:
PostgreSQL 9.3的新功能:

LATERAL關鍵字

左| 對| 內部加入橫向

INNER JOIN LATERALCROSS APPLY相同
LEFT JOIN LATERALOUTER 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 

我喜歡Erwin 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上進行了測試

該鏈接似乎顯示了如何在Postgres 9.0+中做到這一點:

PostgreSQL:參數化遞歸CTE

在標題為“使用集返回函數仿真交叉應用”的頁面中,它位於頁面的下方。 請確保在示例之后記下限制列表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM