这个查询是否相同?不存在并留下外部连接配方

时间:2013-01-16 10:53:30

标签: sql oracle outer-join not-exists

我想拍摄ENI_MONITOR的每一个记录,这是一个孤儿。在ENI_FLUSSI_HUB中,相应的记录不应存在。这两种配方都是正确的吗?左外连接如何思考?

SELECT /*+ PARALLEL (mon, 10) */
       COUNT(1)
FROM   B
WHERE  B.mon_flag_ann = 'N'
       AND NOT EXISTS
           (
               SELECT /*+  PARALLEL (c, 10)  */
                      1
               FROM   A
               WHERE  B.MON_ID_MESSAGGIO = A.flh_id_messaggio
                      AND B.MON_COD_TP_PROCESSO = A.flh_tipo_processo_cod
                      AND A.FLH_FLAG_ANN = 'N'
           );


SELECT /*+ PARALLEL (mon, 10) parallel (c 10) */
       COUNT(DISTINCT MON_MONITORAGGIO_ID)
FROM   B,
       A
WHERE  B.mon_flag_ann = 'N'
       AND B.MON_ID_MESSAGGIO = A.flh_id_messaggio(+)
       AND B.MON_COD_TP_PROCESSO = A.flh_tipo_processo_cod(+)
       AND A.FLH_FLAG_ANN(+) = 'N'
       AND A.flh_id_messaggio(+) IS NULL

2 个答案:

答案 0 :(得分:1)

这两个在功能上是等价的,除非在代码为NULL的情况下。 SQL是描述性语言,而不是过程语言。语法描述结果集,而不是(必然)描述处理的完成方式。

这里有多种方法来编写这样的查询(包括not in版本)。查询的执行方式取决于引擎选择的路径。 Here是一些选择。如果您使用Google,则会针对查询的不同配方提供更多具体效果时间示例。

第二种结构不是编写外连接查询的好方法。以下是首选语法:

SELECT /*+ PARALLEL (mon, 10) parallel (c 10) */
       COUNT(DISTINCT MON_MONITORAGGIO_ID)
FROM   B left outer join
       A
       on B.MON_ID_MESSAGGIO = A.flh_id_messaggio and
          B.MON_COD_TP_PROCESSO = A.flh_tipo_processo_cod and
          A.FLH_FLAG_ANN = 'N'
WHERE  B.mon_flag_ann = 'N' and
       A.flh_id_messaggio IS NULL

答案 1 :(得分:1)

它们是不同的,但更容易理解为什么在转换为ASNSI连接语法时,正如Gordon Linoff所示。在该表格中,您的第二个查询将变为:

SELECT /*+ PARALLEL (mon, 10) parallel (c 10) */
       COUNT(DISTINCT MON_MONITORAGGIO_ID)
FROM   B
LEFT JOIN A
    ON A.flh_id_messaggio = B.MON_ID_MESSAGGIO
    AND A.flh_tipo_processo_cod = B.MON_COD_TP_PROCESSO
    AND A.FLH_FLAG_ANN = 'N'
    AND A.flh_id_messaggio IS NULL
WHERE  B.mon_flag_ann = 'N'

外部联接条件包括A.flh_id_messaggio = B.MON_ID_MESSAGGIO A.flh_id_messaggio IS NULL,这两者都不是真的。 (即使B.MON_ID_MESSAGGIO为null,这也会失败,因为您无法使用=来比较空值。因此,外部联接永远不会找到匹配项,也可能会被省略,因此您将从MON_MONITORAGGIO_ID计算所有不同的B值。

但是,如果您将IS NULL检查结果移至WHERE子句(正如Gordon所做的那样):

SELECT /*+ PARALLEL (mon, 10) parallel (c 10) */
       COUNT(DISTINCT MON_MONITORAGGIO_ID)
FROM   B
LEFT JOIN A
    ON A.flh_id_messaggio = B.MON_ID_MESSAGGIO
    AND A.flh_tipo_processo_cod = B.MON_COD_TP_PROCESSO
    AND A.FLH_FLAG_ANN = 'N'
WHERE  B.mon_flag_ann = 'N'
    AND A.flh_id_messaggio IS NULL

...然后外部连接条件可以找到匹配项。如果找不到匹配项,则在评估WHERE子句时,A.flh_id_messaggio现在确实为null,因此这就像您原来的NOT EXISTS

还假设MON_MONITORAGGIO_ID是唯一的,很可能就是这种情况。但由于你只计算没有匹配的时候,我认为你不需要DISTINCT