我有这个 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