Oracle:如何做一个大的外部加入

时间:2012-08-06 09:12:40

标签: sql oracle

我希望即使违反了ELF表的JOIN条件,也要显示ROPT表中的所有记录。

  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; 

4 个答案:

答案 0 :(得分:2)

您需要了解您的查询

通过将(+)放入elf的直接连接中,您已成功提及"我不在乎精灵是否有数据,我想显示ropt row"

  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 to forn,最后forn to 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

因此,连接循环间接地将elf加入ropt。一种方法是将elf的外部联接也用于forn,但最后理解你的需求然后连接表是有意义的。

- 编辑 -

正如所指出的那样,我们不能有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;

答案 1 :(得分: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子句中放置表'elf'的两个条件会强制'elf'被视为内部连接。自我注意:将来尝试减少教学......: - )

答案 2 :(得分: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; 

答案 3 :(得分:0)

如果我理解你的问题,你想使用LEFT JOIN