使用group by和conditions

时间:2017-02-03 12:30:25

标签: mysql sql group-by database-optimization

你好StackOverflowers:D

我有两个表fichesfiches_actionsfiches_actions表中的条目是对fiches表中的条目所做的操作,每个操作都有{{1}代表行动。

这是两个表的架构

schema of the two tables

问题

对于每一个fiche,获取最后一个动作(action_id),然后获取每个动作的计数。

另一种表述:计算在fiches上所做的每一个动作

我通过在action_id表格中为最后一个fiches_actions

输入最后一个ID来获取最后一个动作

那些小丑必须验证一些条件

max(fiches_actions.id)

我的解决方案

我确实通过使用此方法获得了结果:

首先,我创建了一个视图,以获取对其进行操作的所有活动

`fiches`.`created_at` >= '2016-01-01 00:00:00'
    AND `fiches`.`created_at` <= '2017-02-01 00:00:00'
    AND `fiches`.`status` = 0 
    AND `fiches`.`agent_id` = '51'

然后,我从这个视图中选择计数

 CREATE VIEW v_fiches_actions AS 
  SELECT max(fiches_actions.id) as id, 
    `fiches_actions.action_id`,
     fiches_actions.fiche_id 
 FROM fiches_actions group by fiche_id;

这是我得到的结果:这似乎是正确的

select v_fiches_actions.action_id, count(*) from v_fiches_actions where fiche_id in 
( select `fiches`.`id` from fiches where
    `fiches`.`created_at` >= '2016-01-01 00:00:00'
    AND `fiches`.`created_at` <= '2017-02-01 00:00:00'
    AND `fiches`.`status` = 0 
    AND `fiches`.`agent_id` = '51'
) group by action_id;

我的问题

1-我的方法是否正确,我得到了正确的结果

2-有没有办法在单个查询中执行此操作(不使用视图)

提前谢谢

2 个答案:

答案 0 :(得分:2)

您的方法并不正确,但它更冗长,需要的工作量超出必要的范围。

这是另一种方法:

select fa.action_id, count(*)
from fiches_actions fa join
     fiches f
     on fa.fiche_id = f.id
where f.created_at >= 2016-01-01' and
      f.created_at <= '2017-02-01' and
      f.status = 0 and
      f.agent_id = 51 and
      fa.created_at = (select max(fa2.created_at)
                       from fiches_actions fa2
                       where fa2.fiche_id = f.id
                      )
group by action_id;

对于效果,fiches(agent_id, status, created_at, id)fiches_actions(fiche_id, created_at)上的索引。

相关子查询(特别是正确的索引)应该比聚合快得多。为什么?相关子查询仅在过滤器后保留的行上运行。另一方面,聚合必须聚合fiche_actions表中的所有行。

注意:

  • 您不需要查询视图。
  • 对于日期常数,您不需要时间。
  • 表别名使查询更容易编写和阅读。
  • 假设id是数字,请不要使用51的单引号。仅对字符串和日期常量使用单引号。

答案 1 :(得分:1)

如果id是可用于连接表的主键,则可以在不使用两个选项的情况下进行。

你可以在没有第二次选择的情况下完成:

CREATE VIEW col1, col2, count(*) as new_col AS SELECT FROM Table1 INNER JOIN OtherTable ON ID = ID WHERE created_at.table1 BETWEEN 2016-01-01 AND 2017-02-01 AND status.table1 =o AND agent_id.table1 = 51 AND..