2012-08-06 35 views
0

我希望即使違反了ELF表的JOIN條件,也要顯示ROPT表中的所有記錄。Oracle:如何創建一個大外連接

SELECT 1  
    FROM conf_raggr_opztar ropt, 
      tar_opzioni_tariffarie opt, 
      conf_raggruppamenti_forn rgf, 
      conf_forniture_rel_ragg forg, 
      conf_forniture forn, 
      conf_elementi_fatturabili elf, 
      tar_voci_fatturabili vof, 
      base_fasce_orarie fas 
    WHERE  ropt.opt_opzione_tariffaria_id = opt.opt_opzione_tariffaria_id 
      AND rgf.rgf_raggruppamento_forn_id = ropt.rgf_raggruppamento_forn_id 
      AND forg.rgf_raggruppamento_forn_id = rgf.rgf_raggruppamento_forn_id 
      AND forg.forn_fornitura_id = forn.forn_fornitura_id 
      AND forn.forn_fornitura_id = 'QJlXmOFZPF3eAlAG' 
      AND elf.ROPT_RAGGR_OPZTAR_ID(+) = ropt.ropt_raggr_opztar_id 
      AND elf.COID_CONTRATTUARIO_ID(+) = ropt.COID_CONTRATTUARIO_ID 
      AND elf.ROPT_DATA_INI(+) = ropt.ROPT_DATA_INI 
      AND elf.edw_partition = forn.EDW_PARTITION 
      AND elf.elf_flag_ann(+) = 'N' 
      And elf.ELF_DATA_VER_FIN = to_date('31/12/9999','DD/MM/YYYY') 
      AND elf.VOF_VOCE_FATTURABILE_ID = vof.VOF_VOCE_FATTURABILE_ID 
      AND fas.FAS_FASCIA_ORARIA_ID = elf.FAS_FASCIA_ORARIA_ID 
ORDER BY ELF_VERSIONE desc; 

* ANSI JOIN VERSION(它就像第一個)

SELECT 1 
FROM CONF_RAGGR_OPZTAR ropt 
    INNER JOIN TAR_OPZIONI_TARIFFARIE OPT 
    ON (ropt.OPT_OPZIONE_TARIFFARIA_ID = opt.OPT_OPZIONE_TARIFFARIA_ID) 
    INNER JOIN CONF_RAGGRUPPAMENTI_FORN rgf 
    ON (rgf.RGF_RAGGRUPPAMENTO_FORN_ID = ropt.RGF_RAGGRUPPAMENTO_FORN_ID) 
    INNER JOIN CONF_FORNITURE_REL_RAGG forg 
    ON (forg.RGF_RAGGRUPPAMENTO_FORN_ID = rgf.RGF_RAGGRUPPAMENTO_FORN_ID) 
    INNER JOIN CONF_FORNITURE forn 
    ON (forg.FORN_FORNITURA_ID = forn.FORN_FORNITURA_ID) 
    LEFT OUTER JOIN CONF_ELEMENTI_FATTURABILI elf 
    ON (elf.ROPT_RAGGR_OPZTAR_ID = ropt.ROPT_RAGGR_OPZTAR_ID AND 
     elf.COID_CONTRATTUARIO_ID = ropt.COID_CONTRATTUARIO_ID AND 
     elf.ROPT_DATA_INI = ropt.ROPT_DATA_INI AND 
     elf.EDW_PARTITION = forn.EDW_PARTITION) 
-- LEFT OUTER JOIN TAR_VOCI_FATTURABILI vof 
--  ON (elf.VOF_VOCE_FATTURABILE_ID = vof.VOF_VOCE_FATTURABILE_ID) 
-- LEFT OUTER JOIN BASE_FASCE_ORARIE fas 
--  ON (fas.FAS_FASCIA_ORARIA_ID = elf.FAS_FASCIA_ORARIA_ID) 
    WHERE forn.FORN_FORNITURA_ID = 'QJlXmOFZPF3eAlAG' AND 
     elf.ELF_FLAG_ANN = 'N' AND 
     elf.ELF_DATA_VER_FIN = TO_DATE('31/12/9999','DD/MM/YYYY') 
ORDER BY ELF_VERSIONE DESC; 
+3

無論你有精靈。如果條件不滿足,您需要附加(+)以獲得空記錄。 [採用ansi連接語法會對你有好處,因爲它會使這種錯誤更加清晰。 – 2012-08-06 09:19:38

+0

問題是oracle「說ORA-01417:一個表可能被外連接到最多一個其他表」。這是問題:AND elf.edw_partition(+)= forn.EDW_PARTITION – Revious 2012-08-06 09:47:00

+0

使用'LEFT JOIN'代替'(+)'。我認爲這沒有這個限制。 – 2012-08-06 10:20:31

回答

0

如果我明白你的問題正確,你想用一個LEFT JOIN

2

你需要了解你的查詢

通過直接連接的小精靈將(+),您已經成功地提到,「我不關心,如果精靈有數據,我想表明ROPT行」

AND elf.ROPT_RAGGR_OPZTAR_ID(+) = ropt.ropt_raggr_opztar_id 
    AND elf.COID_CONTRATTUARIO_ID(+) = ropt.COID_CONTRATTUARIO_ID 
    AND elf.ROPT_DATA_INI(+) = ropt.ROPT_DATA_INI 

但是你不知道的是,你有一個間接的加入以及

ROPT加入到RGF

AND rgf.rgf_raggruppamento_forn_id = ropt.rgf_raggruppamento_forn_id 

RGF加入到forg,forg到福爾最後福爾向ELF

AND forg.rgf_raggruppamento_forn_id = rgf.rgf_raggruppamento_forn_id 
AND forg.forn_fornitura_id = forn.forn_fornitura_id 
AND elf.edw_partition = forn.EDW_PARTITION 

所以加入間接聯接小精靈週期ROPT。其中一種方法是讓外部連接讓小精靈進行僞造,但最後,理解你的需求並加入表格將是有意義的。

- 編輯 -

正如指出的是,我們不能有2個外部連接,一個(醜陋的)解決方法可以是這樣的

SELECT 1  
    FROM 
      tar_opzioni_tariffarie opt, 
      conf_raggruppamenti_forn rgf, 
      conf_forniture_rel_ragg forg, 
      conf_forniture forn, 
      (
      select * from //or columns needed 
     conf_raggr_opztar ropt, 
      conf_elementi_fatturabili elf where 
     elf.ROPT_RAGGR_OPZTAR_ID(+) = ropt.ropt_raggr_opztar_id 
      AND elf.COID_CONTRATTUARIO_ID(+) = ropt.COID_CONTRATTUARIO_ID 
      AND elf.ROPT_DATA_INI(+) = ropt.ROPT_DATA_INI 
      ) elf_ropt, 
      tar_voci_fatturabili vof, 
      base_fasce_orarie fas 
    WHERE  elf_ropt.opt_opzione_tariffaria_id = opt.opt_opzione_tariffaria_id 
      AND rgf.rgf_raggruppamento_forn_id = elf_ropt.rgf_raggruppamento_forn_id 
      AND forg.rgf_raggruppamento_forn_id = rgf.rgf_raggruppamento_forn_id 
      AND forg.forn_fornitura_id = forn.forn_fornitura_id 
      AND forn.forn_fornitura_id = 'QJlXmOFZPF3eAlAG' 
      AND elf_ropt.edw_partition(+) = forn.EDW_PARTITION 
      AND elf_ropt.elf_flag_ann(+) = 'N' //is this needed actually? 
      And elf_ropt.ELF_DATA_VER_FIN = to_date('31/12/9999','DD/MM/YYYY') 
      AND elf_ropt.VOF_VOCE_FATTURABILE_ID = vof.VOF_VOCE_FATTURABILE_ID 
      AND fas.FAS_FASCIA_ORARIA_ID = elf_ropt.FAS_FASCIA_ORARIA_ID 
ORDER BY ELF_VERSIONE desc; 
+0

我的要求是將所有綁定到FORN的ropt,並且如果它們存在綁定到ropt的所有精靈。 我想要做這樣的事情:AND elf.edw_partition(+)= forn.EDW_PARTITION – Revious 2012-08-06 09:51:20

+0

這很美!你爲什麼說這很醜? – Revious 2012-08-06 10:10:14

+0

@ Gik25我們有兩個外部連接與同一個表(這是不允許的)。所以我們有點愚蠢的甲骨文:) – Kamal 2012-08-06 10:13:45

2

我建議你學習和使用ANSI-如INNER JOIN,LEFT OUTER JOIN等,它們比將所有內容放入WHERE子句更清晰易懂。在發言的情況下,我相信它可以被重寫如下:

SELECT 1 
    FROM CONF_RAGGR_OPZTAR ropt 
    INNER JOIN TAR_OPZIONI_TARIFFARIE OPT 
    ON (ropt.OPT_OPZIONE_TARIFFARIA_ID = opt.OPT_OPZIONE_TARIFFARIA_ID) 
    INNER JOIN CONF_RAGGRUPPAMENTI_FORN rgf 
    ON (rgf.RGF_RAGGRUPPAMENTO_FORN_ID = ropt.RGF_RAGGRUPPAMENTO_FORN_ID) 
    INNER JOIN CONF_FORNITURE_REL_RAGG forg 
    ON (forg.RGF_RAGGRUPPAMENTO_FORN_ID = rgf.RGF_RAGGRUPPAMENTO_FORN_ID) 
    INNER JOIN CONF_FORNITURE forn 
    ON (forg.FORN_FORNITURA_ID = forn.FORN_FORNITURA_ID) 
    LEFT OUTER JOIN CONF_ELEMENTI_FATTURABILI elf 
    ON (elf.ROPT_RAGGR_OPZTAR_ID = ropt.ROPT_RAGGR_OPZTAR_ID AND 
     elf.COID_CONTRATTUARIO_ID = ropt.COID_CONTRATTUARIO_ID AND 
     elf.ROPT_DATA_INI = ropt.ROPT_DATA_INI AND 
     elf.EDW_PARTITION = forn.EDW_PARTITION AND 
     elf.ELF_FLAG_ANN = 'N' AND 
     elf.ELF_DATA_VER_FIN = TO_DATE('31/12/9999','DD/MM/YYYY')) 
    LEFT OUTER TAR_VOCI_FATTURABILI vof 
    ON (elf.VOF_VOCE_FATTURABILE_ID = vof.VOF_VOCE_FATTURABILE_ID) 
    LEFT OUTER BASE_FASCE_ORARIE fas 
    ON (fas.FAS_FASCIA_ORARIA_ID = elf.FAS_FASCIA_ORARIA_ID) 
    WHERE forn.FORN_FORNITURA_ID = 'QJlXmOFZPF3eAlAG' 
    ORDER BY ELF_VERSIONE DESC; 

注意,上面的WHERE子句中的三個比較可以投入的加入 - 我把它們在WHERE子句中展示你可以這樣做。我懷疑優化器會使用這些比較,但它想要的。

分享和享受。

----編輯

還要注意,把兩個條件表「小精靈」逼「小精靈」的WHERE子句中被視爲彷彿它是內加入。注意自我:嘗試在將來少一點說教...... :-)

+0

謝謝,但它確實提取了ELF的記錄。我報告了這個問題的最後一個表述。 – Revious 2012-08-06 14:04:42

+0

DOH !!!對我來說略有疏忽 - 我應該把'精靈'的所有條件都加入到OUTER JOIN中。嘗試重新制定的查詢。 – 2012-08-06 17:20:50

+0

它的工作原理!這是我所缺少的:另外請注意,在WHERE子句中放置表'elf'的兩個條件迫使'elf'被視爲內部連接 – Revious 2012-08-07 08:04:33

1

很可能使用ANSI JOIN的USING construct以及使用子查詢將使您的查詢更容易編寫。

看看這個示例它應該讓你的查詢工作。

SELECT 1 
FROM CONF_RAGGR_OPZTAR ropt 
    JOIN TAR_OPZIONI_TARIFFARIE OPT using (OPT_OPZIONE_TARIFFARIA_ID) 
    JOIN CONF_RAGGRUPPAMENTI_FORN rgf using (RGF_RAGGRUPPAMENTO_FORN_ID) 
    JOIN CONF_FORNITURE_REL_RAGG forg using (RGF_RAGGRUPPAMENTO_FORN_ID) 
    JOIN CONF_FORNITURE forn using (FORN_FORNITURA_ID) 
    LEFT JOIN (
      select * 
      from CONF_ELEMENTI_FATTURABILI 
      where ELF_FLAG_ANN = 'N' 
       AND ELF_DATA_VER_FIN = TO_DATE('31/12/9999','DD/MM/YYYY') 
     ) elf using (ROPT_RAGGR_OPZTAR_ID,COID_CONTRATTUARIO_ID,ROPT_DATA_INI,EDW_PARTITION) 
-- LEFT OUTER JOIN TAR_VOCI_FATTURABILI vof 
--  ON (elf.VOF_VOCE_FATTURABILE_ID = vof.VOF_VOCE_FATTURABILE_ID) 
-- LEFT OUTER JOIN BASE_FASCE_ORARIE fas 
--  ON (fas.FAS_FASCIA_ORARIA_ID = elf.FAS_FASCIA_ORARIA_ID) 
WHERE FORN_FORNITURA_ID = 'QJlXmOFZPF3eAlAG' 
ORDER BY elf.ELF_VERSIONE DESC; 

無論如何,如果你不選擇從CONF_ELEMENTI_FATTURABILI任何列你爲什麼要外連接表上的?

難道不是沒意思嗎? 你會得到相同的結果,除了與以下查詢重複:

SELECT 1 
FROM CONF_RAGGR_OPZTAR ropt 
    JOIN TAR_OPZIONI_TARIFFARIE OPT using (OPT_OPZIONE_TARIFFARIA_ID) 
    JOIN CONF_RAGGRUPPAMENTI_FORN rgf using (RGF_RAGGRUPPAMENTO_FORN_ID) 
    JOIN CONF_FORNITURE_REL_RAGG forg using (RGF_RAGGRUPPAMENTO_FORN_ID) 
    JOIN CONF_FORNITURE forn using (FORN_FORNITURA_ID) 
-- LEFT OUTER JOIN TAR_VOCI_FATTURABILI vof 
--  ON (elf.VOF_VOCE_FATTURABILE_ID = vof.VOF_VOCE_FATTURABILE_ID) 
-- LEFT OUTER JOIN BASE_FASCE_ORARIE fas 
--  ON (fas.FAS_FASCIA_ORARIA_ID = elf.FAS_FASCIA_ORARIA_ID) 
WHERE FORN_FORNITURA_ID = 'QJlXmOFZPF3eAlAG' 
ORDER BY null DESC; 
+0

SELECT 1僅用於簡短。真正的查詢選擇了很多東西。 – Revious 2012-08-06 18:49:12

+1

接下來只是一個建議:不要刪除簡化問題複雜性的事情,這可能會導致解決方案不能解決您的問題!使用*會更好。 – 2012-08-06 20:40:27