Sql 甲骨文:如何做一个大的外部连接
我希望显示ROPT表中的所有记录,即使违反了ELF表的连接条件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
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。我