AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 287133
Accepted
artfulrobot
artfulrobot
Asked: 2021-03-17 07:50:59 +0800 CST2021-03-17 07:50:59 +0800 CST 2021-03-17 07:50:59 +0800 CST

LEFT JOIN 子查询在主查询中存在 EXISTS 子句时失败

  • 772

我有这个查询:

SELECT c.id contact_id, engagement.sent
FROM contact c
LEFT JOIN (
    /* ➊ Inner query */
    SELECT eq.contact_id contact_id, COUNT(*) sent
    FROM mailing_job j
    INNER JOIN mailing_event_queue eq ON eq.job_id = j.id
    WHERE j.end_date > NOW() - INTERVAL 3 MONTH
    GROUP BY eq.contact_id
  ) engagement ON engagement.contact_id = c.id

 WHERE
  /* ➋ various conditions on table 'c' */
 do_not_email = 0 AND is_opt_out = 0 AND is_deceased = 0 AND is_deleted = 0
   AND contact_type = 'Individual'

   /* ➌ */
   AND EXISTS (
      SELECT gc.contact_id
      FROM group_contact gc
      WHERE gc.contact_id = c.id AND gc.group_id IN (30,386,14,6,214,5,88,361,334,18,9,17,240,7,13,10,292,291,290,12)
    )

   /* ➍ AND c.id=1 */
ORDER BY c.id
  • 内部查询 ➊ 自行运行时会产生结果,例如sent: 15 for contact 1。这是正确的、预期的数据。
  • 但是,运行整个查询会为整个发送的列提供NULL!这让我很烦恼。
  • 消除 ➋ 处的 WHERE 子句,或消除 ➌ 处的 EXISTS,或包括注释掉的 ➍ 子句会导致其运行并返回sent: 15用于测试联系人。

我在 MariaDB 10.3 上。

编辑

希望增加清晰度。从根本上说,这很奇怪——我认为——而且可能是 MariaDB 中的一个错误,尽管我希望不会!

内部查询 ➊ 返回行,例如

contact_id  sent
1           15
...

主查询还使用 ID 获取联系人1。

现在在我所有的岁月里,当我离开加入一个主键(即c.id)上的表时,子查询中的记录匹配,它从来没有改变它的值。

这些值随着其他 WHERE 子句的变化而变化,但在某种程度上仍然意味着外部查询会生成匹配的联系人 ID,我认为这很奇怪。

我真的希望我做了一些愚蠢的事情,但我看不到它。

mysql mariadb
  • 2 2 个回答
  • 93 Views

2 个回答

  • Voted
  1. Best Answer
    ypercubeᵀᴹ
    2021-03-17T11:33:02+08:002021-03-17T11:33:02+08:00

    这看起来像一个错误。请向 MariaDB 发送错误报告。一些细节:

    首先,确保它是一个错误。

    查询 A 生成单行(假设contact (id)具有唯一(或主键)约束:

    -- Query A 
    SELECT c.id contact_id
    FROM contact c
    
     WHERE
      /* ➋ various conditions on table 'c' */
     c.do_not_email = 0 AND c.is_opt_out = 0 AND c.is_deceased = 0 AND c.is_deleted = 0
       AND c.contact_type = 'Individual'
    
       /* ➌ */
       AND EXISTS (
          SELECT gc.contact_id
          FROM group_contact gc
          WHERE gc.contact_id = c.id AND gc.group_id IN (30,386,14,6,214,5,88,361,334,18,9,17,240,7,13,10,292,291,290,12)
        )
    
       /* ➍ */
       AND c.id=1
    ORDER BY c.id ;
    

    查询 B 产生一行(值15在 中sent)

    -- Query B
    /* ➊ Inner query */
    SELECT eq.contact_id contact_id, COUNT(*) sent
    FROM mailing_job j
    INNER JOIN mailing_event_queue eq ON eq.job_id = j.id
    WHERE j.end_date > NOW() - INTERVAL 3 MONTH
      AND eq.contact_id = 1
    GROUP BY eq.contact_id ;
    

    查询 C 生成单行但具有值NULL(或与查询 B 中的值不同的任何内容15)。

    -- Query C 
    SELECT c.id contact_id, engagement.sent
    FROM contact c
    LEFT JOIN (
        /* ➊ Inner query */
        SELECT eq.contact_id contact_id, COUNT(*) sent
        FROM mailing_job j
        INNER JOIN mailing_event_queue eq ON eq.job_id = j.id
        WHERE j.end_date > NOW() - INTERVAL 3 MONTH
        GROUP BY eq.contact_id
      ) engagement ON engagement.contact_id = c.id
        
     WHERE
      /* ➋ various conditions on table 'c' */
     c.do_not_email = 0 AND c.is_opt_out = 0 AND c.is_deceased = 0 AND c.is_deleted = 0
       AND c.contact_type = 'Individual'
    
       /* ➌ */
       AND EXISTS (
          SELECT gc.contact_id
          FROM group_contact gc
          WHERE gc.contact_id = c.id AND gc.group_id IN (30,386,14,6,214,5,88,361,334,18,9,17,240,7,13,10,292,291,290,12)
        )
    
       /* ➍ */
       AND c.id=1
    ORDER BY c.id ;
    

    如果确实发生了上述情况,则几乎可以肯定是表/索引中的错误或损坏的数据。

    其他要检查/添加到报告中的事项:

    • 所有查询的执行计划(使用EXPLAIN SELECT ...)
    • 完成CREATE TABLE所有涉及的表,包括索引。你可以使用SHOW CREATE TABLE tablename ;它。
    • 您的 MariadDB 的确切版本(尝试select version();)。
    • 如果可能,请尝试删除并重新创建涉及的表(不是表!)上的索引,然后再次测试。
    • 如果您没有运行最新的 10.3,请尽可能尝试升级到最新的 10.3,然后再次测试。
    • 如果您有更新主要版本(10.4 或 10.5)的可用服务器,请尝试使用相同数据重新创建表并再次测试。
    • 尝试删除条件(如您所做的那样)或重写 C 并测试它是否产生不同的计划以及正确或错误的结果,例如:
      • 删除其中的每一项:

          do_not_email = 0 AND is_opt_out = 0 AND is_deceased = 0 AND is_deleted = 0
          AND contact_type = 'Individual'
        
      • 去除ORDER BY

      • 删除子查询 3 和/或 4。

      • 在 b 子查询中添加条件:

          LEFT JOIN (
              /* ➊ Inner query */
              SELECT eq.contact_id contact_id, COUNT(*) sent
              FROM mailing_job j
              INNER JOIN mailing_event_queue eq ON eq.job_id = j.id
              WHERE j.end_date > NOW() - INTERVAL 3 MONTH
                AND eq.contact_id = 1
              GROUP BY eq.contact_id
            ) engagement ON engagement.contact_id = c.id
        
      • 将整个查询重写为:

          -- Query Z
          SELECT z.contact_id, engagement.sent
          FROM
              (
              SELECT c.id contact_id
              FROM contact c
        
               WHERE
                /* ➋ various conditions on table 'c' */
               c.do_not_email = 0 AND c.is_opt_out = 0 AND c.is_deceased = 0 AND c.is_deleted = 0
                 AND c.contact_type = 'Individual'
        
                 /* ➌ */
                 AND EXISTS (
                    SELECT gc.contact_id
                    FROM group_contact gc
                    WHERE gc.contact_id = c.id AND gc.group_id IN (30,386,14,6,214,5,88,361,334,18,9,17,240,7,13,10,292,291,290,12)
                  )
        
                 /* ➍ */
                 AND c.id=1
              ) AS z
              LEFT JOIN (
                  /* ➊ Inner query */
                  SELECT eq.contact_id contact_id, COUNT(*) sent
                  FROM mailing_job j
                  INNER JOIN mailing_event_queue eq ON eq.job_id = j.id
                  WHERE j.end_date > NOW() - INTERVAL 3 MONTH
                  GROUP BY eq.contact_id
                ) engagement ON engagement.contact_id = z.contact_id
              ;
        
      • 结合上述任何或所有重写和测试执行计划和结果,并将未能产生正确结果的那些(查询和计划)添加到报告中。

    建议在最新的子版本中进行测试,因为这可能是一个已修复的错误。

    • 1
  2. Rick James
    2021-03-18T08:29:59+08:002021-03-18T08:29:59+08:00

    试试这个 C 的重新表述:

    -- Query C 
    SELECT  c.id contact_id, 
            ( SELECT COUNT(*)
                FROM mailing_event_queue eq
                JOIN mailing_job AS j  ON eq.job_id = j.id
                WHERE  eq.contact_id = c.id 
                  AND  j.end_date > NOW() - INTERVAL 3 MONTH
            ) AS sent
        FROM contact c
        WHERE  /* ➋ various conditions on table 'c' */
         ... (as before)
    
    • 0

相关问题

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

  • 什么时候是使用 MariaDB 而不是 MySQL 的合适时机,为什么?

  • 组如何跟踪数据库架构更改?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve