Sql 甲骨文:如何做一个大的外部连接

Sql 甲骨文:如何做一个大的外部连接,sql,oracle,Sql,Oracle,我希望显示ROPT表中的所有记录,即使违反了ELF表的连接条件 SELECT 1 FROM conf_raggr_opztar ropt, tar_opzioni_tariffarie opt, conf_raggruppamenti_forn rgf, conf_forniture_rel_ragg forg, conf_forniture forn, c

我希望显示ROPT表中的所有记录,即使违反了ELF表的连接条件

  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版本(其作用类似于第一个版本)


如果我正确理解了您的问题,您希望使用
左连接

如果我正确理解了您的问题,您希望使用
左连接
您需要理解您的查询

通过将(+)放在elf的直接联接中,您已经成功地提到“我不在乎elf是否有数据,我想显示ropt行”

但你没有意识到的是,你也有一个间接连接

ropt加入rgf

AND rgf.rgf_raggruppamento_forn_id = ropt.rgf_raggruppamento_forn_id
rgf加入forg,forg加入forn,最后forn加入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进行外部连接,但最终理解您的需求并连接表是有意义的

--编辑--

正如前面指出的,我们不能有两个外部联接,一个(丑陋的)解决方法可以是

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;

您需要理解您的查询

通过将(+)放在elf的直接联接中,您已经成功地提到“我不在乎elf是否有数据,我想显示ropt行”

但你没有意识到的是,你也有一个间接连接

ropt加入rgf

AND rgf.rgf_raggruppamento_forn_id = ropt.rgf_raggruppamento_forn_id
rgf加入forg,forg加入forn,最后forn加入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进行外部连接,但最终理解您的需求并连接表是有意义的

--编辑--

正如前面指出的,我们不能有两个外部联接,一个(丑陋的)解决方法可以是

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;

我建议您学习并使用ANSI风格的联接运算符,如内部联接、左外部联接等。它们比将所有内容放入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子句以证明您可以这样做。我怀疑优化器会按照自己的意愿使用这些比较

分享和享受

----编辑


还要注意的是,将表“elf”的两个条件放在WHERE子句中会强制将“elf”视为内部联接。自我提醒:以后尽量少说教一点…:-)

我建议您学习并使用ANSI风格的连接运算符,如内部连接、左侧外部连接等。它们比将所有内容放入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子句以证明您可以这样做。我怀疑优化器会按照自己的意愿使用这些比较

分享和享受

----编辑

还要注意的是,将表“elf”的两个条件放在WHERE子句中会强制将“elf”视为内部联接。自我提醒:以后尽量少说教一点…:-)

使用ANSI JOIN和子查询可能会使您的查询更容易编写

看看这个示例,它应该可以让您的查询正常工作

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; 
使用ANSI连接和子查询可能会使您的查询更容易编写

看看这个示例,它应该可以让您的查询正常工作

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; 

无论你在哪里,精灵。如果不满足条件,则需要追加(+)以获取空记录。因为它使这类错误变得更加清楚。问题是oracle“说ORA-01417:一个表最多可以外部连接到另一个表”。这就是问题所在:和elf.edw_分区(+)=用于n.edw_分区使用
左连接
而不是
(+)
。我想这没有限制。@a_horse_没有名字:我可以修改它吗?无论你在哪里有精灵。如果不满足条件,则需要追加(+)以获取空记录。因为它使这类错误变得更加清楚。问题是oracle“说ORA-01417:一个表最多可以外部连接到另一个表”。这就是问题所在:和elf.edw_分区(+)=用于n.edw_分区使用
左连接
而不是
(+)
。我想这没有限制。@horse没有名字:我可以修改它吗?我的要求是把所有的ropt绑定到一个FORN上,如果它们存在的话,把所有的elf绑定到ropt上。我想这样做:和elf.edw_分区(+)=forn.edw_PARTITION@Gik25我们在同一个表中有2个外部联接(这是不允许的)。所以我们是在愚弄甲骨文:)我不明白甲骨文的选择。。。我认为这是一个限制。通常情况下,外部连接比内部连接更耗时。虽然有人声称外部联接在某些情况下更快,但我个人的经验是,如果应用于非常大的表,外部联接会使查询速度变慢。如果我尝试在N个大型表上使用外部联接,那么最终将使用NMO*P。。在最坏的情况下使用行,这会使查询速度更慢。所以我假设,为了避免这种情况,oracle给了我们这个限制,我的要求是将所有ropt绑定到FORN,如果它们存在,则将所有elf绑定到ropt。我