【问题标题】:Are this query identical? Not exist and left outer join formulation这个查询是否相同?不存在和左外连接公式
【发布时间】:2012-12-30 16:05:42
【问题描述】:

我想获取 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

【问题讨论】:

  • @Glk25 。 . .字段 flh_id_messaggio 是否采用 NULL 值?
  • @GordonLinoff 没有。所有这些字段都不能为空。

标签: sql oracle outer-join not-exists


【解决方案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

【讨论】:

  • 下同,不等价,或者你的 SQL不等价。我这么说是因为您将 ̉̉is null 从 (+) 移到了 ̉wherẻ
  • @Plouf! - 这更接近 OP 的第一个查询。如果在外部连接条件上A 中没有匹配项,则在评估where 子句时,A.flh_id_messaggionull - 相当于not exists。但是不,OP 的两个查询是不等价的,因为第二个查询是同时比较 A.flh_id_messaggionullB.MON_ID_MESSAGGIO, and it can't be equal to something and null`。我认为这就是您在另一条评论中的意思。
  • @Plouf!我不是很明白。我可以说我对第二个查询的表述与第一个查询不同。但我不明白为什么。 Gordon Linoff 配方有效吗?为什么我的配方没有?
  • @AlexPoole 你不能在评论中回答吗?两种说法不等价?我无法想象为什么。
【解决方案2】:

它们是不同的,但正如 Gordon Linoff 所展示的那样,当转换为 ASNSI 连接语法时,更容易理解为什么。在这种形式下,您的第二个查询变为:

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 为空,这也会失败,因为您不能使用= 来比较空值)。所以外连接永远找不到匹配项,不妨省略,因此您将计算来自B 的所有不同的MON_MONITORAGGIO_ID 值。

但是,如果您将 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

... then 外连接条件可以找到匹配项。如果没有找到匹配项,则在评估 WHERE 子句时,A.flh_id_messaggio 现在确实是 null,所以这就像你原来的 NOT EXISTS

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

【讨论】:

  • 但是,在我的公式中,左外连接将 ENI_MONITOR 的每条记录与 ENI_FLUSSI_HUB 的所有其他记录一起使用是否正确。笛卡尔积。然后通过以下规则细化搜索: A.flh_id_messaggio = B.MON_ID_MESSAGGIO AND A.flh_tipo_processo_cod = B.MON_COD_TP_PROCESSO 或以下规则,b.rowid 为空?
  • @Gik25 - 不,它不形成笛卡尔积;旧式 Oracle 特定的 (+) 表示法仍然根据连接条件进行外连接,特别是 A.flh_id_messaggio = B.MON_ID_MESSAGGIOA.flh_tipo_processo_cod = B.MON_COD_TP_PROCESSO。但这也使A.flh_id_messaggio IS NULL 成为连接条件,并且永远无法满足;我的(和 Gordon 的)版本在左连接之后使它成为 过滤器,而不是连接本身的一部分。
猜你喜欢
  • 2019-10-03
  • 2023-03-25
  • 1970-01-01
  • 2018-03-05
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
  • 2013-02-25
  • 1970-01-01
相关资源
最近更新 更多