简体   繁体   中英

SQL query to count the number of rows in different columns with group by clauses

In my Mysql database, I have 2 columns that store the start and end date of the process, respectively. I need to write a query that allows me to count the number of rows for each month in each column, and presents the count separately.

Table example:

+----+------------+----------------+
| id | startData  |     endData    |
+----+-------------+----------------+
|  1 | 02/03/2020 |    02/03/2020  | 
|  2 | 02/04/2020 |    02/04/2020  |
|  3 | 02/04/2020 |    02/05/2020  |
|  4 | 02/04/2020 |    02/05/2020  |
|  5 | 02/05/2020 |    02/06/2020  |
|  6 | 02/05/2020 |    02/06/2020  |
|  7 | 02/06/2020 |    02/07/2020  |
+----+-------------+----------------+

I want as a result:

+-------+--------------------+-------------------+
| month |  count_month_start |  count_month_end  |
+-------+--------------------+-------------------+
|  03   |         01         |          01       |
|  04   |         03         |          01       |
|  05   |         02         |          02       |
|  06   |         01         |          02       |
|  07   |         00         |          01       |
+-------+--------------------+-------------------+

Assuming your start date and end date columns are of datatype date, you can do -

Select ifnull(Tb1.mn,Tb2.mn) As mn, ifnull(count_mn_start,0) As count_mn_start, ifnull(count_mn_end,0) As count_mn_end
 from
 (Select Month(StartDate) as mn, count(id) as count_mn_start
  from
  my_table
 Group by Month(StartDate))Tb1
 left Join (Select Month(EndDate) as mn, count(id) as count_mn_end
  from my_table
  Group by Month(EndDate)) Tb2
  on Tb1.mn = Tb2.mn
UNION
 Select ifnull(Tb1.mn,Tb2.mn) As mn, ifnull(count_mn_start,0) As count_mn_start, ifnull(count_mn_end,0) As count_mn_end
 from
 (Select Month(StartDate) as mn, count(id) as count_mn_start
  from
  my_table
 Group by Month(StartDate))Tb1
 Right Join (Select Month(EndDate) as mn, count(id) as count_mn_end
  from my_table
  Group by Month(EndDate)) Tb2
  on Tb1.mn = Tb2.mn;

DB fiddle - https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=84ecddb9f5ed431ddff6a9eaab87e5df

PS : If your dates only have one year (2020 as your example) this would work, however ideally if you have different years in the data, consider having the year in the output as well and in that case use the same syntax ie Year(datefield) and add it in the select and group by in the sub-queries (same way as month in the above query).

A pretty simple way is to expand the time periods into days using a recursive CTE. Then just aggregate:

with recursive cte as (
      select id, startdate as dte, enddate
      from t
      union all
      select id, dte + interval 1 day, enddate
      from cte
      where dte < enddate
     )
select year(dte), month(dte),
       sum( day(dte) = 1 ) as cnt_start,
       sum( day(dte) = day(last_day(dte)) ) as cnt_end
from cte
group by year(dte), month(dte) ;

Here is a db<>fiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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