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

我究竟做错了什么?或者有什么办法可以更好地做到这一点?

补充:我完全忘记了一个更重要的因素 - 跟踪表有“模块”列,我只需要“联系”模块的结果。因此,换句话说,我需要过滤掉跟踪表中已经存在的客户,但前提是与联系人模块相关联,而不是与任何其他模块相关联。

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. 对于查询在 中找不到匹配行的任何行,tracking table它将生成一个虚拟行,tracking其中包含所有 NULL 值。(这是描述 OUTER JOIN 功能的一种方式。)

现在的“技巧”是丢弃所有匹配的行。我们通过从跟踪表(在 WHERE 子句中)检查客户 ID 的 NULL 值来做到这一点。对于匹配,该列不会为 NULL。(连接谓词中的等号比较向我们保证了这一点。)所以我们知道,如果我们得到 NULL 值t.customers_id,则不存在匹配项。

因此,此查询返回指定的结果集:

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谓词。我们将在 ORDER BY 子句之前添加:

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

要使用NOT IN谓词,再次在 ORDER BY 子句之前添加:

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

(您可能有一些保证 tracking.customers_id 不为空,但在更一般的情况下,子查询不返回 NULL 值很重要,因此我们包含一个 WHERE 子句,以便我们保证这一点。)

使用适当的索引,反连接模式通常比 theNOT EXISTS或 the表现更好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 回答