1

我需要从 mysql 数据库收集数据,以使我们能够向在给定天数内未活跃的客户发送促销电子邮件,但仅限于从未向我们注册促销积分的客户。数据库比较大,有超过50,000个客户,查询没有注册积分的客户的customer_id单独处理一个多小时。所以我想,如果我把范围缩小到在给定时间内没有登录的客户,然后只搜索那些 customer_id,它会更快。但是,我尝试组合这两个查询完全失败,返回“操作数应包含 1 列”错误。

考虑到我需要在查询中接收的数据,是否有可能实现。

第一个需要 1 小时的查询:

SELECT c.customers_id
FROM customers c 
LEFT JOIN codes_redeem_history pc 
ON pc.customer_id=c.customers_id
WHERE pc.customer_id IS NULL

在给定时间内第二次查询客户:

SELECT ci.customers_info_date_of_last_logon, ci.customers_info_id, c.customers_email_address, c.customers_lastname, c.customers_firstname 
FROM customers c, customers_info ci 
WHERE c.customers_id = ci.customers_info_id 
GROUP BY c.customers_email_address 
HAVING max(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
ORDER BY c.customers_lastname, c.customers_firstname ASC

我是如何尝试的,但未能将它们结合起来:

SELECT c.customers_id
FROM customers c 
LEFT JOIN codes_redeem_history pc 
ON pc.customer_id=c.customers_id
WHERE pc.customer_id IS NULL
AND c.customers_id
IN
(Select ci.customers_info_date_of_last_logon, ci.customers_info_id, c.customers_email_address, c.customers_lastname, c.customers_firstname 
FROM customers c, customers_info ci 
WHERE c.customers_id = ci.customers_info_id 
GROUP BY c.customers_email_address 
HAVING max(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
ORDER BY c.customers_lastname, c.customers_firstname ASC)

我可以从错误消息中看到,它不允许在查询的 IN(SELECT ) 部分进行如此复杂的查询,但我不知道如何重新排列它,或者它是否可行。

SQL 大师有什么建议吗?

谢谢

在要求略有变化之后,我可以在这方面提供更多帮助。

除了较早的答案,我尝试稍微更改查询以允许选择时间跨度,而不是将其固定为 30 天。我使用了 HAVING MAX( ci.customers_info_date_of_last_logon ) >= '" . $ndate . "' ,其中 $ndate 是一个包含所需日期的变量。显然它不起作用,因为日期与 30 天不同。我似乎无法使用 WHERE 条件代替 HAVING MAX。有什么解决办法吗?

4

1 回答 1

2

第一个查询需要很长时间才能完成的原因是,我几乎可以肯定,因为您缺少定义它们关系的列的索引,通过执行以下行来更改表,

ALTER TABLE codes_redeem_history ADD INDEX (customer_id);
ALTER TABLE customers ADD INDEX (customers_id);
ALTER TABLE customers_info ADD INDEX (customers_info_id);

完整的查询,

SELECT  c.customers_id
FROM    customers c 
        LEFT JOIN codes_redeem_history pc 
        ON pc.customer_id=c.customers_id
        LEFT JOIN
        (
            Select  c.customers_id 
            FROM    customers c 
                    INNER JOIN customers_info ci
                        ON c.customers_id = ci.customers_info_id 
            GROUP   BY c.customers_email_address 
            HAVING  MAX(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY)
        ) d ON c.customers_id = d.customers_id
WHERE   pc.customer_id IS NULL AND 
        d.customers_id IS NOT NULL

更新 1

SELECT  c.customers_id
FROM    customers c 
        INNER JOIN customers_info ci
            ON c.customers_id = ci.customers_info_id 
        LEFT JOIN codes_redeem_history pc 
            ON c.customers_id = pc.customer_id
WHERE   pc.customer_id IS NULL
GROUP   BY c.customers_email_address 
HAVING  MAX(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY)
于 2013-03-08T00:44:41.903 回答