我有以下声明:
1997年购物的客户的姓名和地址清单。
所以我认为以下两种方法是正确的,但它们并非如此;为什么呢?
select contactname, address from customers
inner join orders
on customers.customerid = orders.customerid
where date_part('year', orderdate) = 1997
order by contactname
select contactname, address from customers
where customerid in
(select customerid from orders
where date_part('year', orderdate) = 1997)
order by contactname
答案 0 :(得分:4)
有很多正确的方法可以做到这一点。 EXISTS
半连接可能是PostgreSQL中最快的,如果你只想要一个不同客户的列表,除了至少存在1个订单之外没有其他详细信息:
SELECT c.contactname, c.address
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customerid = c.customerid
AND o.orderdate >= '1997-1-1'::date
AND o.orderdate < '1998-1-1'::date
)
ORDER BY contactname;
为什么要使用?
WHERE o.orderdate >= '1997-1-1'::date
AND o.orderdate < '1998-1-1'::date
而不是:
WHERE date_part('year', orderdate) = 1997
使用您的表达式PostgreSQL必须在检查条件之前为每一行计算一个值。在替代形式中,列(按原样)与两个常数项匹配。这也可以更容易地使用索引。应该更快。
另请注意我如何使用table aliases来简化查询。
由于JOIN
,您的第一个查询会遇到行的倍增。如果表customer
中的行在表orders
中有多个匹配的行,则每个订单都会得到一行。你可以用GROUP BY
:
SELECT c.contactname, c.address
FROM customers c
JOIN orders o USING (customerid)
WHERE o.orderdate >= '1997-1-1'::date
AND o.orderdate < '1998-1-1'::date
GROUP BY c.customer_id --- or whatever is the primary key of c
ORDER BY c.contactname
..这是另一种方式。但大多数可能更慢。如果您还想从表orders
中检索其他(聚合)数据,则可以使用此表单。
DISTINCT
可以替代GROUP BY
,在这个简单的情况下大致相同。删除此GROUP BY
子句,然后在DISTINCT
之后添加SELECT
。
您还可以使用DISTINCT
修复第二个查询,而是使用我的第一个示例。