0

顧客オーディエンスを選択するクエリを実行しようとしていますが、以前に電子メールを受け取ったことのない顧客を選択する必要があります。電子メール追跡は別のテーブルから取得されます。これは元のクエリです。

SELECT 
  c.customers_firstname, 
  c.customers_lastname, 
  o.orders_id, 
  o.customers_id, 
  c.customers_email_address
FROM 
  orders o, 
  customers c,  
  order_status s
WHERE 
  o.customers_id = c.customers_id
  AND o.orders_id = s.orders_id
  AND o.orders_status = s.orders_status_id 
ORDER BY 
  o.orders_id ASC

ここで、tracking という別のテーブルをチェックして、そのテーブルに顧客が既に存在するかどうかを確認し、存在する場合はスキップする必要があります。

これは私が試したものですが、うまくいかないようです:

SELECT 
   c.customers_firstname, 
   c.customers_lastname, 
   o.orders_id, 
   o.customers_id, 
   c.customers_email_address
FROM 
   orders o, 
   customers c 
INNER JOIN 
   tracking t 
ON 
   c.customers_id = t.customers_id,  
   order_status s
WHERE 
   o.customers_id = c.customers_id
   AND o.orders_id = s.orders_id
   AND o.orders_status = s.orders_status_id
   AND c.customers_id NOT LIKE t.customers_id
ORDER BY 
   o.orders_id ASC

私は何を間違っていますか?または、これをより良く行う方法はありますか?

追加:もう 1 つの重要な要素を完全に忘れていました。追跡テーブルには「モジュール」列があり、「連絡先」モジュールからの結果のみが必要です。つまり、追跡テーブルに既に存在する顧客を除外する必要がありますが、連絡先モジュールに関連付けられている場合にのみ、他のモジュールには関連付けられていません。

4

2 に答える 2

1

これは、元のクエリと同等です。

SELECT c.customers_firstname
     , c.customers_lastname
     , o.orders_id
     , o.customers_id
     , c.customers_email_address
  FROM orders o
  JOIN customers c 
    ON c.customers_id = o.customers_id
  JOIN order_status s 
    ON s.orders_id = o.orders_id
   AND s.orders_status_id = o.orders_status
 ORDER
    BY o.orders_id ASC

アンチジョインを追加します

仕様を満たすために、「アンチジョイン」パターンを使用できます。ORDER BY句の前に、これをクエリに追加できます。

  LEFT
  JOIN tracking t
    ON t.customers_id = o.customers_id
 WHERE t.customers_id IS NULL   

trackingこれにより、に基づいて、テーブルから一致するすべての行が検索されcustomers_idます。クエリで一致する行が見つからない行については、すべてのNULL値で構成されるtracking tableダミー行が生成されます。tracking(これは、OUTER JOINが行うことを説明する1つの方法です。)

ここでの「トリック」は、一致したすべての行を破棄することです。そして、(WHERE句で)追跡テーブルからcustomers_idのNULL値をチェックすることによってそれを行います。一致する場合、その列はNULLにはなりません。t.customers_id(結合述語のequals比較は、それを保証します。)したがって、のNULL値を取得した場合、一致がなかったことがわかります。

したがって、このクエリは指定された結果セットを返します。

SELECT c.customers_firstname
     , c.customers_lastname
     , o.orders_id
     , o.customers_id
     , c.customers_email_address
  FROM orders o
  JOIN customers c 
    ON c.customers_id = o.customers_id
  JOIN order_status s 
    ON s.orders_id = o.orders_id
   AND s.orders_status_id = o.orders_status
  LEFT
  JOIN tracking t
    ON t.customers_id = o.customers_id
 WHERE t.customers_id IS NULL   
 ORDER
    BY o.orders_id ASC

その他のアプローチ

他のアプローチもありますが、多くの場合、アンチジョインが最高のパフォーマンスを発揮します。

他のいくつかのオプションは、NOT EXISTS述語とNOT IN述語です。私はそれらを追加することができますが、私がそれに取り掛かる前に、それらの解決策が他の回答で提供されることを期待しています。


その最初のクエリ(質問のクエリと同等)から始めて、NOT EXISTS述語を使用することもできます。ORDERBY句の前にこれを追加します。

 WHERE NOT EXISTS 
       ( SELECT 1
           FROM tracking t
          WHERE t.customers_id = o.customers_id
       )

述語を使用するにはNOT IN、ここでも、ORDERBY句の前にこれを追加します。

 WHERE o.customers_id NOT IN
       ( SELECT t.customers_id
           FROM tracking t
          WHERE t.customers_id IS NOT NULL
       )

(tracking.customers_idがnullでないことを保証できる場合もありますが、より一般的なケースでは、サブクエリがNULL値を返さないことが重要であるため、WHERE句を含めて保証します。)

適切なインデックスを使用すると、通常、反結合パターンは、NOT EXISTSまたはのいずれよりも優れたパフォーマンスを発揮しますNOT INが、常にそうであるとは限りません。

于 2012-12-18T23:22:26.893 に答える
0

spencer7593 が提案したように、アンチジョインを実行できますが、代わりに

LEFT JOIN tracking t ON t.customers_id = o.customers_id
WHERE t.customers_id IS NULL   

もっと簡単に書くことができます

JOIN tracking t ON t.customers_id = o.customers_id
于 2012-12-18T23:39:54.370 に答える