Percona MySql 5.6,linux x64。
我们有一个customers_history
表,用于跟踪客户随时间的变化。我们想要做的是在特定月份内按供应商(lead_source_id)计算更改。
+--------+-------------+----------------+---------------------+--------+
| id | customer_id | lead_source_id | repurchased_date | Rating |
+--------+-------------+----------------+---------------------+--------+
| 422923 | 420450 | 4 | 2014-04-14 09:16:48 | Warm |
| 422924 | 420450 | 4 | 2014-04-14 09:16:48 | Cold |
| 422956 | 420450 | 4 | 2014-04-14 09:16:49 | Hot |
| 422933 | 420451 | 37 | 2014-04-14 09:18:41 | Hot |
| 422938 | 420452 | 1 | 2014-04-10 20:50:30 | Hot |
| 422984 | 420452 | 1 | 2014-04-12 20:50:30 | Hot |
| 422940 | 420453 | 47 | 2014-04-14 09:20:27 | Hot |
+--------+-------------+----------------+---------------------+--------+
鉴于上述示例,我们想要的是此报告,报告由供应商(lead_source_id)进行的回购。什么资格作为回购是在repurchase_date更新时。只改变评级不算数。
+----------------+-------+
| lead_source_id | count |
+----------------+-------+
| 4 | 2 |
| 37 | 1 |
| 1 | 2 |
| 47 | 1 |
+----------------+-------+
我们最初尝试过这个:
SELECT count(DISTINCT(ch.repurchased_date))
FROM customers_history ch
WHERE Year(ch.repurchased_date) = 2014
AND Month(ch.repurchased_date) = 4
AND ch.lead_source_id IS NOT NULL;
但是,计数与将where子句更改为SELECT DISTINCT(ch.created_at)), lead_source_id
时返回的行数不同。
无论如何,我们在一个试图解决这个问题的泡菜罐子里。非常感谢任何帮助或指示。
CRAP。对不起,伙计们,谢谢你们到目前为止的答案,但我完全不知道为什么这个问题如此严重。这实际上是一个历史表,它记录来自多个列的更改。我编辑了原来的问题。
注意当评级发生变化时,repurchased_date不会发生变化。我们希望从计数中排除行422923,但计算行422924和422956。
答案 0 :(得分:1)
我不确定自己得到了什么。 不过你的意思是这个吗?
SELECT ch.lead_source_id, count(*)
FROM customers_history ch
WHERE
Year(ch.created_at) = 2014 AND
Month(ch.created_at) = 4 AND ch.lead_source_id IS NOT NULL
GROUP BY ch.lead_source_id;
答案 1 :(得分:1)
您的查询看起来非常接近。我认为所需要的只是添加GROUP BY
条款。
COUNT(DISTINCT foo)
将有效地"崩溃"相同的值,以便计数仅对每个:组增加1:相同的日期值。
根据示例数据和所需的结果集,这应该有效:
SELECT ch.lead_source_id
, COUNT(DISTINCT ch.repurchased_date)
FROM customers_history ch
WHERE ch.repurchased_date >= '2014-04-01'
AND ch.repurchased_date < '2014-04-01' + INTERVAL 1 MONTH
AND ch.lead_source_id IS NOT NULL
GROUP
BY ch.lead_source_id
在示例数据中,customer_id
和lead_source_id
相互关联。 (可能是因为样本量很小......)
(有关索引,索引范围扫描和使用覆盖索引的GROUP BY优化的其他注释,请参阅下面的注释。)
问题更新之前的答案
这是返回指定结果的一种方法,除了排序,我无法识别模式......
SELECT ch.lead_source_id
, COUNT(1) AS count_
FROM customers_history ch
WHERE ch.cust_updated_at >= '2014-04-01'
AND ch.cust_updated_at < '2014-04-01' + INTERVAL 1 MONTH
AND ch.lead_source_id IS NOT NULL
GROUP BY ch.lead_source_id
ORDER BY ?
<强>更新强>
如果你想要&#34;计算&#34;要cust_updated_at
,请在GROUP BY
中添加该列。例如,如果对于此示例数据:
+--------+-------------+----------------+---------------------+
| id | customer_id | lead_source_id | cust_updated_at |
+--------+-------------+----------------+---------------------+
| 422924 | 420450 | 4 | 2014-04-14 09:16:48 |
| 422956 | 420450 | 4 | 2014-04-14 09:16:48 |
| ?????? | 420450 | 4 | 2014-04-15 22:22:22 |
+--------+-------------+----------------+---------------------+
您想要返回:
+----------------+-------+
| lead_source_id | count |
+----------------+-------+
| 4 | 2 |
| 4 | 1 |
+----------------+-------+
然后,将 cust_updated_at
列添加到 GROUP BY
子句中,例如
SELECT ch.lead_source_id
, COUNT(1) AS count_
FROM customers_history ch
WHERE ch.cust_updated_at >= '2014-04-01'
AND ch.cust_updated_at < '2014-04-01' + INTERVAL 1 MONTH
AND ch.lead_source_id IS NOT NULL
GROUP
BY ch.lead_source_id
, ch.cust_updated_at
备注:强>
(如果我们不使用ORDER BY
子句,GROUP BY
子句隐式在同一组表达式上应用ORDER BY
。我们只需要指定ORDER BY
获得不同排序的子句。)
此外,在谓词中的函数中包装日期列可以防止MySQL通过使用索引范围扫描来满足谓词。我们通常喜欢&#34;裸日期列&#34;在谓词中,并且在常数方面需要进行任何操作。 (将日期列包含在函数中,如YEAR()
强制MySQL为表中的每一行(或者不被另一个谓词过滤掉的每一行)评估该函数。
为获得最佳效果,此查询的合适覆盖索引将为:
... ON customer_history (lead_source_id, created_at)
MySQL可以完全从索引中满足查询;解释输出将显示&#34;使用索引&#34;。如果我们不使用ORDER BY子句,MySQL将避免使用&#34;使用filesort&#34;也是如此。