0

我有以下声明:

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
4

1 回答 1

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 必须在检查条件之前为每一行计算一个值。在替代形式中,列(原样)与两个常数项匹配。这也可以更轻松地使用索引。应该更快。

还要注意我如何使用表别名使查询更易于阅读。

您的第一个查询由于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 BYthis 的子句并添加DISTINCTafter SELECT

您也可以使用 修复您的第二个查询DISTINCT,而是使用我的第一个示例。

于 2012-11-05T00:28:39.087 回答