我有这个 LEFT JOIN 对吗?

Posted

技术标签:

【中文标题】我有这个 LEFT JOIN 对吗?【英文标题】:Do I have this LEFT JOIN right? 【发布时间】:2011-09-25 18:33:13 【问题描述】:

我需要查找在给定日期之后创建但尚未订购的客户总数。

我有两张桌子:

|客户 | // 还有更多,但仅此而已 +----+------+---------+ // 你需要回答这个问题 |身份证 |姓名 |创建 | +----+------+---------+ |订单 | // 还有更多,但仅此而已 +----+-------------+ // 你需要回答这个问题 |身份证 |客户 ID | +----+--------------+

我需要查找在给定日期之后创建但尚未订购的客户总数。

这就是我所做的:

选择计数(*) 来自客户 在customers.ID = orders.customer_id 上左加入订单 WHERE customers.Created > #任意日期# AND orders.ID 为空;

我确信这是正确的,但它似乎并没有产生正确的结果。我的意思是我的老板正在查看结果并告诉我,根据经验,未订购的新客户注册数量远远超过此查询产生的数量。

那么我这样做对吗?如果我是,我显然需要看看还有什么可能导致问题。谢谢。

编辑 1

下面的评论表明orders.id 不可为空。可能是这种情况,但是如果我检查 orders.customer_id Is Null 是否会得到相同的结果。

编辑 2

我不想让事情变得过于复杂,但如果您知道我在 Access 数据库中执行此操作可能会很有用,因此我无法使用标准 SQL 允许的所有好东西。 (我已经编辑了标签)

【问题讨论】:

我没有看到任何错误。问问你的老板他的经验是从哪里来的:) 【参考方案1】:

你的老板必须告诉你他认为什么是“好的价值观”。

也许他曾经有一个报告与其他过滤器一起计算此客户。也许您必须检查订单表中某处的价格,如果价格 = 0,则认为不是真正的订单。

根据您给我们的信息,您的查询是绝对正确的,也许我会补充一点:

SELECT Count(DISTINCT customers.ID)
FROM customers
    LEFT JOIN orders 
        ON customers.ID = orders.customer_id
WHERE customers.Created > #arbitrary date#
AND orders.ID Is Null;

为了便于维护和理解(查询应该会慢一点,但不会那么慢)

【讨论】:

他可能更喜欢COUNT(*) AS Count_Customers_Without_Orders 您知道 Access 不支持COUNT(DISTINCT <col>)吗?【参考方案2】:

我想知道它们是否是您的代码中等待发生的微妙错误。

规范声明“查找客户总数”。通过加入orders 表,您实际上是指望加入。当然,对于没有订单的客户,您确实在计算客户数。但是,对于有订单的客户,您将计算他们的订单。

我更喜欢反映客户数量的查询构造,以便我(或者实际上是更随意的用户)可以将反连接切换为半连接并获得预期的结果(使用您的构造,他们会获得误导性的计数) 例如

SELECT COUNT(*)
  FROM customers
 WHERE customers.Created > #specific date#
       AND NOT EXISTS (
                       SELECT *
                         FROM orders
                        WHERE orders.customer_id = customers.ID
                      );

至于接受的答案,我提供了“为了更容易维护和理解”(查询可能会慢一点,但希望不会慢很多)。”

【讨论】:

谢谢@onedaywhen。我认为你的答案是正确的,这就是我最初所做的。是速度问题导致我改用左连接。但是,它并没有明显更快,两者都非常慢,所以无论如何我可能会重新这样做。【参考方案3】:

也许您的代码在某处允许为客户记录订单(但未完成)。 您可以计算仅订购了 0 个订单的客户。

SELECT COUNT(*)
FROM
  ( SELECT customers.id
    FROM customers
      INNER JOIN orders ON customers.ID = orders.customer_id
    WHERE customers.Created > #arbitrary date# 
    GROUP BY customers.id
    HAVING COUNT(IIF(orders.amount > 0, 1, NULL)) = 0  
  ) AS grp

Access 没有CASE 语句,但它有一个IIF() 函数。

需要INNER JOIN 而不是JOIN

【讨论】:

谢谢,不幸的是,如果我尝试这样做,它会说我的FROM 子句中有语法错误。我怀疑这是因为我正在 MS Access 中尝试这个,这是一堆粪便。 @MrMisterMan:更新了 Ms-Access 的查询。 @ypercube 恐怕还是没有运气。 MS Access 的错误消息没有提供任何错误的线索,这无济于事。不过,我感谢您的帮助。 @MrMisterMan:orders.amount 是个猜测。我想你有一些领域有这样的信息。我已经测试了上述内容。我不明白为什么它在你的机器上不起作用。 @ypercube 我将orders.amount 替换为表的等价物customers.Total,但它不起作用。我确定我搞砸了,因为我不怀疑你的代码是好的。感谢您的帮助:)【参考方案4】:

不,这是不对的。

试试这个:

SELECT
SUM(CASE WHEN (SELECT COUNT(*) FROM orders WHERE customers.ID = orders.customer_id) = 0 
  THEN 1
  ELSE 0
END) 
FROM customers
WHERE customers.Created > #arbitrary date#

【讨论】:

@David-W-Fenton 我想他可能在我澄清它是特定于 Access 之前提供了这个答案。【参考方案5】:

看看this website,它解释了sql连接之间的所有差异

【讨论】:

有问题的联接是反联接,但链接的文章没有提及这一点,而是使用更适合EXCEPT 关系运算符的图片/示例(在 SQL 中:SELECT * FROM TableA EXCEPT SELECT * FROM TableB;)。跨度> 我链接到它以显示不同连接背后的集合论,我相信它会帮助大多数人遇到类似问题,他们试图找出每个表的哪些部分出来连接的结果。

以上是关于我有这个 LEFT JOIN 对吗?的主要内容,如果未能解决你的问题,请参考以下文章

MS Access INNER JOIN/LEFT JOIN 问题

在 Redshift 上混合使用 CROSS JOIN 和 LEFT JOIN

LEFT JOIN查询的执行时间太长

Left Join - 在 Eloquent 中

为啥这个 LEFT JOIN 会消除另一个表中没有任何内容的记录?

left join分页查询