使用UNION的SQL查询工作,但是当我用MINUS替换时不起作用

时间:2012-02-24 19:45:41

标签: mysql

我正在尝试为没有仅在3个月内下订单的帐户的客户的电子邮件创建续集查询。如果我进行查询

SELECT checkouts.email 
FROM orders, checkouts 
WHERE orders.id = checkouts.order_id AND orders.user_id is NULL 
AND orders.created_at < CURDATE() - INTERVAL 3 MONTH

我收到的所有电子邮件均来自过去3个月内没有帐户的订单,它没有考虑过去3个月内没有来自相同电子邮件的帐户的订单sql查询电子邮件列表。因此,我想使用MINUS运算符从最近的订单中减去所有电子邮件。当我尝试这个时,我收到一个错误:

SELECT checkouts.email 
FROM orders, checkouts 
WHERE orders.id = checkouts.order_id AND orders.user_id is NULL 
AND orders.created_at < CURDATE() - INTERVAL 3 MONTH 
MINUS 
SELECT checkouts.email 
FROM orders, checkouts 
WHERE orders.id = checkouts.order_id AND orders.user_id is NULL 
AND orders.created_at > CURDATE() - INTERVAL 3 MONTH

如果我使用UNION而不是MINUS运行相同的查询,它可以正常工作,并且无论日期如何,基本上都可以从没有帐户的订单中提供所有电子邮件。

为什么UNION工作而不是MINUS?我如何修复此查询,以便我可以让MINUS工作?

2 个答案:

答案 0 :(得分:1)

尝试使用此构造(可能有更好的执行计划以及其他说法):

SELECT checkouts.email 
FROM orders, checkouts 
WHERE orders.id = checkouts.order_id AND orders.user_id is NULL 
AND orders.created_at < CURDATE() - INTERVAL 3 MONTH 
AND checkouts.email NOT IN (
    SELECT checkouts.email 
    FROM orders, checkouts 
    WHERE orders.id = checkouts.order_id AND orders.user_id is NULL 
    AND orders.created_at > CURDATE() - INTERVAL 3 MONTH
)

您可能还想为checkouts.email IS NULL添加处理,因为那不会是非(如果该措辞有意义),因为NULL永远不会=或&lt;&gt;任何事情。

SELECT checkouts.email 
FROM orders, checkouts 
WHERE orders.id = checkouts.order_id AND orders.user_id is NULL 
AND orders.created_at < CURDATE() - INTERVAL 3 MONTH 
AND (
    checkouts.email IS NULL
    OR
    checkouts.email NOT IN (
        SELECT checkouts.email 
        FROM orders, checkouts 
        WHERE orders.id = checkouts.order_id AND orders.user_id is NULL 
        AND orders.created_at > CURDATE() - INTERVAL 3 MONTH
    )
)

您可能还会考虑更简单:

SELECT checkouts.email, MAX(orders.created_at)
FROM orders, checkouts 
WHERE orders.id = checkouts.order_id AND orders.user_id is NULL
GROUP BY checkouts.email 
HAVING MAX(orders.created_at) < CURDATE() - INTERVAL 3 MONTH 

答案 1 :(得分:0)

MySQL不进行日期算术...你必须使用DATE_ADD()或DATE_SUB(),例如

DATE_ADD( CURDATE(), INTERVAL 3 MONTH )
DATE_SUB( CURDATE(), INTERVAL 3 MONTH )

此外,日期可以是PITA。如果created_at包含时间,则需要确保获得DATE ONLY部分,因此它意味着12:00:00 AM(使用CURDATE()函数即可)。但是,与您的结束日期相似...如果您的结束日期是2012年2月24日,但想要包括截至2012年2月24日晚上11:59:59,那么您最好不要超过一天... ex: &LT; 2012年2月25日