Php SQL查询在哪里不同

Php SQL查询在哪里不同,php,mysql,sql,Php,Mysql,Sql,我试图运行一个查询来选择客户受众,但它应该选择以前没有收到电子邮件的客户。电子邮件跟踪来自另一个表。这是原始查询: 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.custom

我试图运行一个查询来选择客户受众,但它应该选择以前没有收到电子邮件的客户。电子邮件跟踪来自另一个表。这是原始查询:

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
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
现在,我需要检查另一个名为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
我做错了什么?或者有没有更好的办法


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

这相当于您最初的查询:

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
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   
 WHERE NOT EXISTS 
       ( SELECT 1
           FROM tracking t
          WHERE t.customers_id = o.customers_id
       )
 WHERE o.customers_id NOT IN
       ( SELECT t.customers_id
           FROM tracking t
          WHERE t.customers_id IS NOT NULL
       )
接下来要做的是根据
客户id
跟踪
表中查找所有匹配行。对于查询在
跟踪表
中未找到匹配行的任何行,它将从
跟踪
生成一个包含所有空值的虚拟行。(这是描述外部联接功能的一种方式。)

现在的“诀窍”是扔掉所有匹配的行。我们通过检查跟踪表(在WHERE子句中)中customers_id的空值来实现这一点。对于匹配,该列不会为空。(连接谓词中的equals比较保证了这一点。)因此我们知道,如果我们得到
t.customers\u 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

其他办法 还有其他方法,但反连接通常表现最好

其他一些选项包括
不存在
谓词和
不在
谓词。我可以补充这些,不过我希望在我开始之前,其他答案会提供这些解决方案


从第一个查询开始(相当于您问题中的查询),我们还可以使用
notexists
谓词。我们将在“订购方式”条款之前添加以下内容:

  LEFT
  JOIN tracking t
    ON t.customers_id = o.customers_id
 WHERE t.customers_id IS NULL   
 WHERE NOT EXISTS 
       ( SELECT 1
           FROM tracking t
          WHERE t.customers_id = o.customers_id
       )
 WHERE o.customers_id NOT IN
       ( SELECT t.customers_id
           FROM tracking t
          WHERE t.customers_id IS NOT NULL
       )
要使用
NOT IN
谓词,请再次在ORDER BY子句之前添加:

  LEFT
  JOIN tracking t
    ON t.customers_id = o.customers_id
 WHERE t.customers_id IS NULL   
 WHERE NOT EXISTS 
       ( SELECT 1
           FROM tracking t
          WHERE t.customers_id = o.customers_id
       )
 WHERE o.customers_id NOT IN
       ( SELECT t.customers_id
           FROM tracking t
          WHERE t.customers_id IS NOT NULL
       )
(您可以在一定程度上保证tracking.customers\u id不为null,但在更一般的情况下,子查询不返回null值是很重要的,因此我们包含了一个WHERE子句,以保证这一点。)


有了适当的索引,反连接模式通常比
不存在
不在
中表现更好,但并不总是如此。

如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

不要混合隐式连接和显式连接。你做了额外的努力,所以我删除了我的答案,因为它涵盖了相同的领域。您可以包括讨论查询计划差异的内容。您还可以讨论为什么原始查询没有work@Conrad弗里克斯:我不是有意否定你的回答,对此我深表歉意。我只是想解释一下反连接模式,并提供一些替代方案。这个链接提供了一个关于差异的很好的描述。不用担心:)你的回答让我的回答变得多余,只是变成了噪音。“仅仅因为我的头发老了几分钟,并不意味着它就应该留下来。”斯宾塞7593哇,令人印象深刻的回答!谢谢你花时间写这篇文章!我很确定这是正确的答案,但它对我来说仍然不起作用,显然是因为我刚才在我的原始问题中添加了这个原因。我可以请你检查我添加的内容并更新你的答案吗?我尝试添加{其中t.module像'contact'和t.customers\u id为NULL}但这不起作用,它会过滤所有客户,因为他们的id与其他模块关联。。。谢谢大家!@user1078494:请理解,当您向WHERE子句添加
t.somecol IS NOT NULL
谓词时(这是像'contact'这样的
t.module所做的),这将否定外部联接。生成的伪行将包含
t
表中所有列的空值,因此添加到WHERE子句将导致查询从不返回任何行。您需要将
和t.module(如“contact”
谓词)添加到
左JOIN
ON
子句中(将其添加到WHERE子句前面的一行)