与 MySQL 不存在斗争

Posted

技术标签:

【中文标题】与 MySQL 不存在斗争【英文标题】:Struggling with MySQL NOT EXISTS 【发布时间】:2015-10-05 15:42:21 【问题描述】:

我正在尝试查询我们的数据库以提取客户数据。关键部分是:

拉出所有未购买product_a的客户/订单。

这将列出已购买 product_b、product_c 和 product_d 的客户/订单。

但它需要确保客户从未购买过product_a。我需要排除它们。

这是处理“不存在”的正确方法吗?我仍然觉得它包括一些购买 product_a 的记录。

SELECT
    *
FROM
    orders
JOIN customers AS cus ON orders.CustomerNumber = cus.CustomerNumber
WHERE
    product != 'product_a'
OR (
    HomeTelephone = ''
    AND MobileTelephone != ''
)
AND NOT EXISTS  (
    SELECT
        OrderNumber
    FROM
        orders AS o
    JOIN customers AS c ON o.CustomerNumber = c.CustomerNumber
    WHERE
        c.EmailAddress = cus.EmailAddress
    AND Product = 'product_a'
    AND completed = 1
)
ORDER BY
    orderdate

如果没有 NOT EXISTS 语句,即使他们单独购买了 product_a,也可以包含客户记录,对吗?

【问题讨论】:

你的问题是你的WHERE 子句中的OR。它将包括那些具有HomeTelephone = '' AND MobileTelephone != '' 的记录。您对这部分查询的意图是什么? 在 where 子句中... 将括号放在 product 之前和 OR 括号之后,以查看查询处理器实际在做什么。然后分析你真正想要做什么。 OR 的作用可能与您想象的不同。 【参考方案1】:

Your Not Exists 有点偏离,where product != 'product_a' 是多余的。

SELECT
    *
FROM

    orders AS o1
    JOIN customers AS cus ON o1.CustomerNumber = cus.CustomerNumber
WHERE
    cus.HomeTelephone = ''
    AND cus.MobileTelephone != ''
    AND NOT EXISTS  (
        SELECT 
            1 
        FROM 
            orders o2
        WHERE
            o2.CustomerNumber = cus.CustomerNumber 
            AND Product = 'product_a'
            AND completed = 1
    )
ORDER BY
    o1.orderdate

这将为您提供客户的订单。不过,根据您的描述,如果您只想要客户信息,您可以在查询的第一部分排除订单的连接,并使用 Not Exist 来确定该客户是否购买了 product_a。

SELECT
    *
FROM
    customers cus
WHERE
    HomeTelephone = ''
    AND MobileTelephone != ''
    AND NOT EXISTS  (
        SELECT 
            1 
        FROM 
            orders o
        WHERE
            o.CustomerNumber = cus.CustomerNumber 
            AND Product = 'product_a'
            AND completed = 1
    )

【讨论】:

您的第一个查询似乎是要让这个工作的人 - 但子查询正在消失。我不知道我还能做些什么来优化它。没有子它的几秒钟,它似乎无限! 订单表是否有关于 customernumber 的索引?还是产品?还是完成了? 就是这样!!谢谢!现在超级快。 嗨 JamieD77 - 我在我们的订单表中为 CustomerNumber 添加了一个“正常”索引,上面的查询开始绝对飞!但它似乎扼杀了我们在网站上通过 php 运行的 SELECT 查询,该查询只是简单地拉回今天的订单,并与其他表的一些其他连接以提取各种信息。任何想法为什么?今天为了让线上系统顺利运行,不得不删除索引....【参考方案2】:
SELECT c.* 
  FROM customers c
  LEFT
  JOIN orders o
    ON o.CustomerNumber = c.CustomerNumber 
   AND o.product = 'product_a'
 WHERE o.CustomerNumber IS NULL

【讨论】:

以上是关于与 MySQL 不存在斗争的主要内容,如果未能解决你的问题,请参考以下文章

不存在的 MySql 消息错误

优化存在与不存在

命名空间“Microsoft”中不存在类型或命名空间名称“Bot”?

hive中提取年月(与mysql语法存在差异)

mysql中先判断数据是不是存在,如存在则增加数量,不存在则增加一条记录

mysql插入数据时,判断是不是存在,存在则替代,不存在则直接插入,需要能够批量处理。