简体   繁体   English

MySQL Count 和 Convert Row to Colum 只涉及一张表

[英]MySQL Count and Convert Row to Colum Involve One Table Only

I have a table name histories that record user activities which consists of user_id, branch_id and duration.我有一个记录用户活动的表名历史记录,它由 user_id、branch_id 和持续时间组成。

The table look like this:该表如下所示:

+++++++++++++++++++++++++++++++++++
id | user_id | branch_id | totHours
+++++++++++++++++++++++++++++++++++
|1 |   100   |     1     |    1   |
|2 |   199   |     1     |    1   |
|3 |   121   |     1     |    1   |
|4 |   140   |     1     |    1   |
|5 |   103   |     2     |    3   |
|6 |   107   |     2     |    1   |
|7 |   299   |     1     |    2   |
|8 |   209   |     2     |    2   |
|9 |   119   |     1     |    5   |

I would like to produce an output like this:我想产生这样的输出:

+++++++++++++++++++++++++++
Hours | Branch A | Branch B
+++++++++++++++++++++++++++
|1    |    4    |     1   |
|2    |    1    |     1   |
|3    |    0    |     1   |
|4    |    0    |     0   |
|5    |    1    |     0   |

I try make it using this query, but when i use group by on totHours column only, it return error because i need to include the branch_id in the group by.我尝试使用此查询进行操作,但是当我仅在 totHours 列上使用 group by 时,它会返回错误,因为我需要在 group by 中包含 branch_id。

Here is my query:这是我的查询:

select totHours as Hours,
   coalesce(case when branch_id = 1 then count(totHours) else 0 end) as 'Branch A',
   coalesce(case when branch_id = 2 then count(totHours) else 0 end) as 'Branch B'
from histories
group by totHours, branch_id;

And if the totHours is not in the table (for example in this table 4), it will display 0 for both branch column.如果 totHours 不在表中(例如在此表 4 中),则两个分支列都将显示 0。

Here is my db fiddle这是我的数据库小提琴

Update: MySQL version 5.7.22更新:MySQL 版本 5.7.22

If you're using MySQL version 8+ (or any version support windows function), you can make use of the recursive common table expression to generate the hour values for you then LEFT JOIN table histories with it.如果您使用 MySQL 版本 8+(或任何版本支持 windows 功能),您可以使用递归公用表表达式为您生成小时值,然后使用它LEFT JOINhistories After that you can do SUM() with CASE expression in SELECT to generate your expected output:之后,您可以在SELECT中使用CASE表达式执行SUM()以生成预期的输出:

WITH RECURSIVE hours AS (
    SELECT 1 AS hr, MAX(totHours) AS maxth FROM histories UNION ALL
    SELECT hr+1, maxth FROM hours WHERE hr+1 <= maxth)
SELECT hours.hr, 
       SUM(CASE WHEN histories.branch_id=1 THEN 1 ELSE 0 END) AS Branch_A,
       SUM(CASE WHEN histories.branch_id=2 THEN 1 ELSE 0 END) AS Branch_B
FROM hours
 LEFT JOIN histories 
 ON hours.hr=histories.totHours
GROUP BY hours.hr;

If you're using version that doesn't support window function, you can create a subquery to represent the hours (including missing hour).如果您使用的版本不支持窗口函数,您可以创建一个子查询来表示小时数(包括缺少的小时数)。 This is a hard-coding approach where you may have to always update the subquery to include new hour value (if any):这是一种硬编码方法,您可能必须始终更新子查询以包含新的小时值(如果有):

SELECT hours.hr, 
       SUM(CASE WHEN histories.branch_id=1 THEN 1 ELSE 0 END) AS Branch_A,
       SUM(CASE WHEN histories.branch_id=2 THEN 1 ELSE 0 END) AS Branch_B
FROM 
    (SELECT 1 hr UNION 
      SELECT 2 UNION 
      SELECT 3 UNION 
      SELECT 4 UNION 
      SELECT 5) AS hours
 LEFT JOIN histories 
 ON hours.hr=histories.totHours
GROUP BY hours.hr;

Demo fiddle 演示小提琴

Edit the hours subquery to add more, for example if you want until 7, you just add:编辑hours子查询以添加更多内容,例如,如果您想要直到 7 点,您只需添加:

(SELECT 1 hr UNION 
      SELECT 2 UNION 
      SELECT 3 UNION 
      SELECT 4 UNION 
      SELECT 5 UNION 
      SELECT 6 UNION 
SELECT 7) AS hours

to the subquery.到子查询。 Another way is to define the hours beforehand and create a reference table.另一种方法是预先定义小时数并创建参考表。 Let's say you estimate the hour to be until 100, then it's better if you create a table that stores 1-100 as reference for the LEFT JOIN假设您估计小时为 100,那么最好创建一个存储 1-100 的表作为LEFT JOIN的参考

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM