这是我要了解的问题:
假设一个网站包含两个表,Customers表和Orders表。
编写SQL查询以查找从未订购任何商品的所有客户。
表:客户。
+----+-------+
| Id | Name |
+----+-------+
| 1 | Joe |
| 2 | Henry |
| 3 | Sam |
| 4 | Max |
+----+-------+
表:订单。
+----+------------+
| Id | CustomerId |
+----+------------+
| 1 | 3 |
| 2 | 1 |
+----+------------+
以上述表格为例,返回以下内容:
+-----------+
| Customers |
+-----------+
| Henry |
| Max |
+-----------+
解决方案:
SELECT Name AS Customers
FROM Customers AS c LEFT JOIN Orders AS o ON c.Id = o.CustomerId
WHERE o.Id IS NULL;
有人知道我们为什么使用c.Id = o.CustomerId
来匹配列,为什么我们选择o.Id为Null而不选择其他列?
答案 0 :(得分:1)
正如Kevin所提到的,CustomerId是Orders表的外键。 left outer join
将两个表与具有在联接条件中指定的匹配数据的行组合在一起;如果没有匹配数据,则为null。这意味着left outer join
使用c.Id = o.CustomerId
将创建以下表格选择:
+------+--------+------+--------------+
| c.Id | c.Name | o.Id | o.CustomerId |
+------+--------+------+--------------+
| 1 | Joe | 2 | 1 |
| 2 | Henry | NULL | NULL |
| 3 | Sam | 1 | 3 |
| 4 | Max | NULL | NULL |
+----+----------+------+--------------+
如果我们使用上表中的where子句WHERE o.Id IS NULL
进行选择,我们将收到ID为2和4的行,因为o.Id
对于这些行为空。
答案 1 :(得分:0)
原因是因为CustomerId
表中的Orders
列是Id
表中Customers
列的外键。因此,要正确连接这两个表,请在这两列上。
我认为这些列的命名不正确,如果在两个表中都使用CustomerId,那将更有意义。
答案 2 :(得分:0)
已经解释了现有查询的工作原理。
我发现not exists
是表达此查询的一种更简单明了的方式:
select c.*
from customers c
where not exists (select 1 from orders o where o.customer_id = c.id)
使用orders(custmer_id)
上的索引,这实际上可能比反左联接解决方案的效果更好。
答案 3 :(得分:-1)
Does anyone know why we are using c.Id = o.CustomerId to match the columns?
因为我们通过这些列生成2个表。我们可能会使用其他产品,并且产品可能会有所不同。
Why we are choosing o.Id to be Null and not the other columns?
这是一个过滤器,您可以使用所需的任何条件,结果集也可以不同。
P.S。在大多数情况下,LEFT会在主键上加入过滤器(但之后会变成INNER JOIN)