2012-07-13 13 views
12

MS SQL Server 2005 için yazılan SQL sorgularını Postgres 9.1'e taşımam gerekir.
Bu sorguda CROSS APPLY yerine en iyi yolu nedir?SQL Server'da CROSS UYGULAMASINA GÜNCELLEŞTİRME

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

GetCitizenRecModified() fonksiyonu bir tablo değerli bir fonksiyondur. Bu işlevin kodunu koyamıyorum çünkü gerçekten çok büyük, bazı zor hesaplamalar yapıyor ve bunu bırakamam.

+0

: iç YANAL

INNER JOIN LATERALCROSS APPLY
ve LEFT JOIN LATERAL aynı aynı

OUTER APPLY olarak Örnek kullanım olduğunu JOIN. Bir işlev işlevini tıpkı bir işlev gibi kullanabilirsiniz. Sadece onlara katıl. –

+0

@a_horse_with_no_name - "CROSS APPLY", TVF'yi bir kez yürütmek yerine ve daha sonra sonuca katılmak yerine ilişkilendirilmiş parametrelerle yeniden çalıştırır. –

cevap

8

9,3 ya da geç bir LATERAL katılmak kullanmak ?


, Sana bir set dönen fonksiyonu (RETURNS TABLE or RETURNS SETOF record OR RETURNS record) ile çalışıyoruz düşüncelerinizi gerçekleştirmek için çok basit bir yolu var:

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

İşlev, o dış sorgu her satır için nce. Fonksiyon birden çok satır döndürürse, sonuçta oluşan satırlar buna göre çarpılır. Tüm parantezleri, bir satır türünün ayrıştırılması için sözdizimsel olarak gereklidir. masa işlevi şöyle görünebilir: Eğer sütunlar aynı seviyede görünmez çünkü WHERE maddesini uygulamak istiyorsanız

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; 

Bir alt sorgu veya CTE sar gerekir. (Eğer fonksiyonun her çıkış sütunu için değerlendirme tekrar önlemek çünkü o, zaten performans için daha iyi): Bu veya benzeri bir şey yapmak için birkaç başka yolları da vardır

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; 

. Her şey tam olarak ne istediğine bağlı.

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

çalıştırırken f_citizen_rec_modified fonksiyonu (v_citizenversions her satırda ile çarpılır) döndürür her kolon için 1 defa ran edilecektir :

+0

Teklif ettiğiniz sorguyu kullandım. Şimdi şok oldum: sorgu bir dakikadan fazla yürütür. ms sql'de bir saniyeden daha az O_O alır. – user1178399

+1

@ user1178399: Oyundaki birçok faktörü bilmeden bunu yorumlamak neredeyse imkansız. Performansın geliştirilebileceğini tahmin ediyorum. –

1

Bu bağlantı 9.0+ Postgres nasıl yapılacağını göstermek için görünür:

PostgreSQL: parameterizing a recursive CTE

It "set dönen fonksiyonları ile GEÇERLİ in taklit ÇAPRAZ" başlıklı bölümde Sayfanın altındaki bu. Örnekden sonra sınırlamaların listesini not ettiğinizden emin olun.

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; 

Neden LEFT JOIN LATERAL ... ON true: Postgres olarak

1

Erwin Brandstetter cevabı ancak, bir performans sorunu keşfettim gibi . Bu etki için belge bulamadım, ancak hata ayıklama yoluyla bunu başardı. Şimdi soru, bu performansın yanıltıcı yan etkisi olmaksızın bu etkinin (yanal birleştirmelerin olduğu 9.3'ten önce) nasıl elde edebiliriz?

Güncelleme: Bir cevap bulmuş gibi görünüyor. Aşağıdaki şekilde, sorgu yeniden yazma:

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 

daha sonra başka bir sütun içine büst o sonuçlar üzerinden seçmek bu sarma temel fark, birinci ham fonksiyon sonuçları elde olmak (iç alt sorgu). Bu PG üzerinde test 9,2

9

Necromancing edildi: PostgreSQL 9.3 içinde
Yeni:

YANAL anahtar bıraktı

| sağ | Çapraz Postgres uygulamak gerekmez

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 
İlgili konular