【问题标题】:MySQL INNER/LEFT JOIN on 3 tables, where records in 3rd table might not existMySQL INNER/LEFT JOIN 在 3 个表上,其中第 3 个表中的记录可能不存在
【发布时间】:2013-08-24 04:57:17
【问题描述】:

我遇到了一个问题,经过多次失败尝试后我似乎无法解决。

我需要对三个表进行连接以进行某些报告,而在第三个表中可能不存在记录。但是如果第三张表中的记录不存在,我需要将第三张表的数据报一个空值,并获取所有符合其他条件的记录。

精简到相关的列,这里是表结构:

成员 - 此表包含注册到网站的所有成员

| memberId  | insertDate          |
| ==========|=====================|
| 1         | 2013-08-01 18:18:16 |
| 2         | 2013-08-02 18:18:16 |
| 3         | 2013-08-03 18:18:16 |
| 4         | 2013-08-04 18:18:16 |
| 5         | 2013-08-05 18:18:16 |

registration_steps - 此表包含注册过程的进度以及注册是否完成

| memberId  | completed |
| ==========|===========|
| 1         | 1         |
| 2         | 1         |
| 3         | 1         |
| 4         | 0         |
| 5         | 1         |

purchases - 这张桌子可以容纳,嗯..购买

| memberId  | insertDate          |
| ==========|=====================|
| 1         | 2013-08-02 18:18:16 |
| 1         | 2013-08-03 17:18:16 |
| 1         | 2013-08-03 18:18:16 |
| 5         | 2013-08-07 18:18:16 |

这是我到目前为止提出的查询:

SELECT `m`.`memberId`,
       DATE(`m`.`insertDate`) AS `regDate`,
       COUNT(`p`.`memberId`) AS `totalTransactions`,
       DATE(MIN(`p`.`insertDate`)) AS `firstPurchaseDate`,
       DATE(MAX(`p`.`insertDate`)) AS `latestPurchaseDate`,
       DATEDIFF(DATE(MIN(`p`.`insertDate`)), DATE(`m`.`insertDate`)) AS `daysBetweenRegAndFirstPurchase`
  FROM `db`.`members` `m`
       INNER JOIN `db`.`registration_steps` `r` ON `m`.`memberId` = `r`.`memberId` 
       INNER JOIN `db`.`purchases` `p` ON `m`.`memberId` = `p`.`memberId`
 WHERE `m`.`insertDate` BETWEEN '2013-07-01 00:00:00' AND '2013-07-31 23:59:59'
   AND `r`.`completed` = 1
GROUP BY `m`.`memberId`
;

它显示了我想要的一切,但在餐桌购买中缺少记录的成员。

这是我得到的:

| memberId  | regDate             | totalTransactions | firstPurchaseDate   | latestPurchaseDate  | daysBetweenRegAndFirstPurchase |
| ==========|=====================|===================|=====================|=====================|================================|
| 1         | 2013-08-01 18:18:16 | 3                 | 2013-08-02 18:18:16 | 2013-08-03 18:18:16 | 1                              |
| 5         | 2013-08-05 18:18:16 | 1                 | 2013-08-07 18:18:16 | 2013-08-07 18:18:16 | 2                              |

但我需要的是:

| memberId  | regDate             | totalTransactions | firstPurchaseDate   | latestPurchaseDate  | daysBetweenRegAndFirstPurchase |
| ==========|=====================|===================|=====================|=====================|================================|
| 1         | 2013-08-01 18:18:16 | 3                 | 2013-08-02 18:18:16 | 2013-08-03 18:18:16 | 1                              |
| 2         | 2013-08-02 18:18:16 | 0                 | NULL                | NULL                | -1                             |
| 3         | 2013-08-03 18:18:16 | 0                 | NULL                | NULL                | -1                             |
| 5         | 2013-08-05 18:18:16 | 1                 | 2013-08-07 18:18:16 | 2013-08-07 18:18:16 | 2                              |

为了实现这一点,我尝试将第二个内连接更改为左连接、左外连接,并将 where 条件置于第一个内连接条件。但是,我无法获得预期的结果。 (必须承认我打断了一些运行时间很长的查询,这些查询可能是正确的(?)(实际情况下的成员总数约为 20k)。)

有人吗?

提前致谢!

【问题讨论】:

  • totalTransactions 来自哪里(COUNT(t.id) AS totalTransactions,)?
  • 你去吧.. 也来自购买表。感谢发现
  • 试试LEFT OUTER JOIN而不是INNER JOIN
  • @DipeshParmar 如前所述,我尝试将第二个内连接更改为左连接、左外连接,并将 where 条件置于第一个内连接条件
  • @eyecatchUp 我是说用左外连接替换所有内连接...你试过了吗..???

标签: mysql join left-join inner-join


【解决方案1】:

要从member 表中获取所有结果,您需要left join 其他表并为member 表添加group by

示例

FROM `db`.`members` `m`
       LEFT OUTER JOIN `db`.`registration_steps` `r` ON `m`.`memberId` = `r`.`memberId` 
       LEFT OUTER JOIN `db`.`purchases` `p` ON `m`.`memberId` = `p`.`memberId`

左[外]

指定将左表中不满足连接条件的所有行都包含在结果集中,并将其他表的输出列设置为NULL,以及内连接返回的所有行。

【讨论】:

    【解决方案2】:

    (假设您查询的日期范围应在 2013 年 8 月和 2013 年 7 月之间)。您需要将针对购买的联接切换为外部联接。这将包括没有任何购买的会员,所以...

       left outer JOIN `purchases` `p` ON `m`.`memberId` = `p`.`memberId`
    

    SQL Fiddle

    【讨论】:

      【解决方案3】:

      (将内连接替换为左连接会得到正确的结果)

      发件人db.membersm 左连接 db.registration_steps r ON m.memberId = r.memberId 左加入db.purchases p ON m.memberId = p.memberId

      或者您可以用左连接单独替换任何购买。

      注意:左连接和左外连接都产生相同的结果,因此您可以使用其中任何一个。

      【讨论】:

        猜你喜欢
        • 2013-04-19
        • 1970-01-01
        • 2019-08-12
        • 1970-01-01
        • 2014-02-21
        • 2016-12-16
        • 1970-01-01
        • 2012-04-04
        • 2012-10-10
        相关资源
        最近更新 更多