MySQL查询使用HAVING和LIMIT子句创建查询摘要行

时间:2016-09-30 05:27:15

标签: mysql

我遇到了解决如何编写MySQL查询的问题,该查询可以为使用HAVING和LIMIT子句的查询创建摘要行。以下是一些示例数据,以便重新创建我的问题..

样本表

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `logins` int(10) unsigned DEFAULT NULL,
  `date` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

样本数据

INSERT INTO `user` (`id`, `logins`, `date`)
VALUES
    (1,1,'2016-09-25'),
    (2,1,'2016-09-25'),
    (3,2,'2016-09-26'),
    (4,2,'2016-09-26'),
    (5,3,'2016-09-27'),
    (6,3,'2016-09-27'),
    (7,4,'2016-09-28'),
    (8,4,'2016-09-28'),
    (9,5,'2016-09-29'),
    (10,5,'2016-09-29');

这是我的基本查询,显示完整结果。

mysql> select `date`, sum(`logins`) `logins` from `user` group by `date`;
+------------+--------+
| date       | logins |
+------------+--------+
| 2016-09-25 |      2 |
| 2016-09-26 |      4 |
| 2016-09-27 |      6 |
| 2016-09-28 |      8 |
| 2016-09-29 |     10 |
+------------+--------+

通过正确的方式获得摘要行没问题。

mysql> select sum(`logins`) `logins` from `user`;
+--------+
| logins |
+--------+
|     30 |
+--------+

但是,如果我想通过下面的查询来构建摘要行呢?在这个例子中,我添加了HAVING和LIMIT子句,用于模拟非常大的数据集。此查询中的HAVING子句表示用户可以更改为接口中提供的过滤器中的最大数量。限制0,2表示结果的第1页(在这种情况下为3:0,2; 2,4; 4,6)。这些查询是用于一次按X,X量显示结果的分页系统的一部分。因此查询中LIMIT子句的原因..

mysql> select `date`, sum(`logins`) `logins` from `user` group by `date` having `logins` <= 8 limit 0, 2;
+------------+--------+
| date       | logins |
+------------+--------+
| 2016-09-25 |      2 |
| 2016-09-26 |      4 |
+------------+--------+

在这种情况下,我需要上述结果集的摘要查询应该记录6次登录。我将如何构建查询以执行此类操作?

现在我不能简单地循环查询结果(客户端或服务器端)来计算总数,因为html表(生成的服务器端)仅显示结果的第一页,而且只计算该特定页面上显示的计数。我需要在表格分页的所有页面上显示一个包含完整数据集计数的摘要行,如果这有意义的话。

更新

以下是所需结果的一种样本。

+------------+--------+
| date       | logins |
+------------+--------+
| 2016-09-25 |      2 |
| 2016-09-26 |      4 |
+------------+--------+
| TOTAL      |     20 | <-- JUST NEED A QUERY TO PRODUCE THIS NUMBER SOME HOW..
+------------+--------+

我很抱歉..我的意思是说20应该是数字,而不是6 ..因为使用HAVING过滤器的完整结果集会如此:

mysql> select `date`, sum(`logins`) `logins` from `user` group by `date` having `logins` <= 8;
+------------+--------+
| date       | logins |
+------------+--------+
| 2016-09-25 |      2 |
| 2016-09-26 |      4 |
| 2016-09-27 |      6 |
| 2016-09-28 |      8 |
+------------+--------+

SORRY!

这几乎就像我需要一个像这样的查询(没有分组):

select `date`, sum(`logins`) `logins` from `user` having `logins` <= 8

但显然这不起作用..

最终更新

嗯,这是我的20基于@ Shadow的答案,这是一个非常简单的例子,但最终引导我得到了我需要的答案:

mysql> select sum(`logins`) `logins` from (select `date`, sum(`logins`) `logins` from `user` group by `date` having `logins` <= 8) t;
+--------+
| logins |
+--------+
|     20 |
+--------+

2 个答案:

答案 0 :(得分:2)

在应用having和limit子句之后,您需要进行总结。在显示数字时在表示层中执行此操作,或者必须在sql中将第二个查询作为子查询,并在外部查询中执行求和。

select sum(logins) as logins from
    (select `date`, sum(`logins`) `logins` from `user` group by `date` having `logins` <= 8 limit 0, 2) t

答案 1 :(得分:0)

您可以使用CROSS JOIN在查询中包含总结果:

select u.`date`, 
       sum(u.`logins`) `logins`,
       t.`total_logins` 
from `user` as u  
cross join (select sum(`logins`) `total_logins` from `user`) as t
group by u.`date` 
having `logins` <= 8 limit 0, 2;

Demo here

修改

您可以使用下面更复杂的查询来获得所需的结果:

select `date`, `logins`
from (
  select `date`, `logins`, @rn := @rn + 1  as rn
  from (
     select case when `date` is null then 'Total' else `date` end as `date`, 
            sum(`logins`) as `logins`
     from (
        select `date`, sum(`logins`) `logins` 
        from `user` 
        group by `date` 
        having `logins` <= 8) as t
     group by `date` with rollup ) as s
  cross join (select @rn := 0) as v       
  order by case when `date` = 'Total' then 1 else 0 end,
           `date`) as x
where x.rn <= 2 or x.`date` = 'Total'  

Demo here