SQL帮助:当日期更新时,如何按组计数?

时间:2014-04-15 23:23:23

标签: mysql sql database tableau

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。

2 个答案:

答案 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_idlead_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;也是如此。