0

私は次のステートメントを持っています:

1997年に購入した顧客の名前と住所のリスト。

したがって、次の2つの方法は正しいと思いましたが、正しくありません。なぜ?

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顧客のリストが必要で、それ以外の注文からの詳細が少なくとも1つ存在しない場合は、半結合がPostgreSQLでおそらく最速です。

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は、条件をチェックする前に、すべての行の値を計算する必要があります。別の形式では、列は(そのままで)2つの定数項と照合されます。これにより、インデックスをより簡単に使用することもできます。より速くする必要があります。

クエリを読みやすくするためにテーブルエイリアスを使用する方法にも注意してください。

最初のクエリは、が原因で行の乗算に悩まされていJOINます。customerテーブル内の行にテーブル内の一致する行が複数ある場合、orders注文ごとに1つの行を取得します。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

DISTINCTGROUP BYこの単純なケースではほとんど同じことを行うのに代わるものです。GROUP BYこの句を削除し、DISTINCT後に追加しSELECTます。

2番目のクエリをで修正することもできますがDISTINCT、最初の例を使用してください。

于 2012-11-05T00:28:39.087 に答える