简体   繁体   中英

count of every day (mysql)

I want get something like this

Mysql data

(dat_reg)
1.1.2000 
1.1.2000 
1.1.2000
2.1.2000
2.1.2000
3.1.2000

I want to get:

   (dat_reg)  (count)
    1.1.2000 -   3
    2.1.2000 -   5
    3.1.2000 -   6

What I tried is this:

SELECT COUNT( * ) as a , DATE_FORMAT( dat_reg, '%d.%m.%Y' ) AS dat 
FROM members 
WHERE (dat_reg > DATE_SUB(NOW() , INTERVAL 5 DAY)) 
GROUP BY DATE_FORMAT(dat_reg, '%d.%m.%Y') 
ORDER BY dat_reg 

but I get:

 1.1.2000 - 3 | 2.1.2000 - 2 | 3.1.2000 - 1 

Some tips how create query for this?

A subquery counting the rows where the registration date is less than or equal to the current registration date could help you out.

SELECT m2.dat_reg,
       (SELECT count(*)
               FROM members m3
               WHERE m3.dat_reg <= m2.dat_reg) count
       FROM (SELECT DISTINCT m1.dat_reg
                    FROM m1.members
                    WHERE m1.dat_reg > date_sub(now(), INTERVAL 5 DAY)) m2
       ORDER BY m2.dat_reg;

(If you got days, on which no one registered and don't want to have gaps in the result, you need to replace the subquery aliased m2 with a table or subquery, that has all days in the respective range.)

I would suggest using variables in MySQL:

SELECT d.*, (@sumc := @sumc + cnt) as running_cnt
FROM (SELECT DATE_FORMAT(dat_reg, '%d.%m.%Y') as dat, COUNT(*) as cnt
      FROM members 
      WHERE dat_reg > DATE_SUB(NOW() , INTERVAL 5 DAY) 
      GROUP BY dat
      ORDER BY dat_reg 
     ) d CROSS JOIN
     (SELECT @sumc := 0) params;

If you want an accumulative from the beginning of time, then you need an additional subquery:

SELECT d.*
FROM (SELECT d.*, (@sumc := @sumc + cnt) as running_cnt
      FROM (SELECT DATE_FORMAT(dat_reg, '%d.%m.%Y') as dat, dat_reg, COUNT(*) as cnt
            FROM members 
            GROUP BY dat
            ORDER BY dat_reg 
           ) d CROSS JOIN
           (SELECT @sumc := 0) params
      ) d
WHERE dat_reg > DATE_SUB(NOW() , INTERVAL 5 DAY)

I believe you can use the window functions to do the work:

mysql> SELECT employee, sale, date, SUM(sale) OVER (PARTITION by employee ORDER BY date) AS cum_sales FROM sales;
+----------+------+------------+-----------+
| employee | sale | date       | cum_sales |
+----------+------+------------+-----------+
| odin     |  200 | 2017-03-01 |       200 |
| odin     |  300 | 2017-04-01 |       500 |
| odin     |  400 | 2017-05-01 |       900 |
| thor     |  400 | 2017-03-01 |       400 |
| thor     |  300 | 2017-04-01 |       700 |
| thor     |  500 | 2017-05-01 |      1200 |
+----------+------+------------+-----------+

In your case you already have the right groups, it is only a matter of specifying the order in which you want the data the be aggregated.

Source: https://mysqlserverteam.com/mysql-8-0-2-introducing-window-functions/

Cheers

Here is a solution using rank and a continuous count variable:

WITH ranked AS (
  SELECT m.* 
    ,ROW_NUMBER() OVER (PARTITION BY m.dat_reg ORDER BY m.id DESC) AS rn
  FROM (
    select id, dat_reg
    ,@cnt := @cnt + 1 AS ccount from members
    ,(SELECT @cnt := 0) var 
   WHERE (dat_reg > DATE_SUB(NOW(), INTERVAL 5 DAY))
  ) AS m
)
SELECT DATE_FORMAT(dat_reg, '%d.%m.%Y') as dat, ccount FROM ranked WHERE rn = 1;

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