skip to Main Content

I have two tables of users and articles and I want to count how many new users and how many new articles I have in the past 7 days.

tbl_users:

[Code, Username, Createdate]

1,David,01/01/2022
2,Henry,02/01/2022

tbl_articles:

[Code, Header, Createdate]

1,Hello,01/01/2022
2,Goodbye,02/01/2022

This query works now but it’s slow and long. Please help me fix this query (I know it’s bad) and if it’s possible to add diff columns for both counters:

(Please go easy on me with the comments)

select articles.days_back,articles.count, users.count as users from (
select 0 as days_back,count(*) as count from tbl_articles where  date(createdate)< date_add(curdate(), interval -0 day)
union all 
select 1,count(*) from tbl_articles where  date(createdate)< date_add(curdate(), interval -1 day)
union all 
select 2,count(*) from tbl_articles where  date(createdate)< date_add(curdate(), interval -2 day)
union all 
select 3,count(*) from tbl_articles where  date(createdate)< date_add(curdate(), interval -3 day)
union all 
select 4,count(*) from tbl_articles where  date(createdate)< date_add(curdate(), interval -4 day)
union all 
select 5,count(*) from tbl_articles where  date(createdate)< date_add(curdate(), interval -5 day)
union all 
select 6,count(*) from tbl_articles where  date(createdate)< date_add(curdate(), interval -6 day)
union all 
select 7,count(*) from tbl_articles where  date(createdate)< date_add(curdate(), interval -7 day)
) as articles
left join 
(
select 0 as days_back,count(*) as count from tbl_users where  date(createdate)< date_add(curdate(), interval -0 day)
union all 
select 1,count(*) from tbl_users where  date(createdate)< date_add(curdate(), interval -1 day)
union all 
select 2,count(*) from tbl_users where  date(createdate)< date_add(curdate(), interval -2 day)
union all 
select 3,count(*) from tbl_users where  date(createdate)< date_add(curdate(), interval -3 day)
union all 
select 4,count(*) from tbl_users where  date(createdate)< date_add(curdate(), interval -4 day)
union all 
select 5,count(*) from tbl_users where  date(createdate)< date_add(curdate(), interval -5 day)
union all 
select 6,count(*) from tbl_users where  date(createdate)< date_add(curdate(), interval -6 day)
union all 
select 7,count(*) from tbl_users where  date(createdate)< date_add(curdate(), interval -7 day)
) as users
on articles.days_back=users.days_back

2

Answers


  1. Something like that?

    SELECT Counter.Articles, Counter.Users (
    SELECT COUNT(1) FROM tbl_articles WHERE DATE(createdate) BETWEEN (CURRENT_TIMESTAMP() AND DATE_ADD(CURRENT_TIMESTAMP(), INTERVAL -7 DAY)) Articles,
    SELECT COUNT(1) FROM tbl_users WHERE DATE(createdate) BETWEEN (CURRENT_TIMESTAMP() AND DATE_ADD(CURRENT_TIMESTAMP(), INTERVAL -7 DAY)) Users
    ) Counter;
    

    haven’t tested it btw

    Login or Signup to reply.
  2. It is not as easy as just use a group by, but as you thought group by is important to do this. I guess there will be no simple 5 line query to get your expected result.
    I would suggest to do multiple queries and some backend code instead of a single query. It is hard to read, understand and maintain.

    But it is possible.

    A GROUP BY DATE_FORMAT(Created,'%Y-%m-%d') in a simple select would already give you the count per day.

    The next problem to solve is, that you want the days_back instead of the date itself. Thats also quite simple with DATEDIFF(DATE_FORMAT(NOW(),'%Y-%m-%d'), DATE_FORMAT(Createdate,'%Y-%m-%d')).

    But the third requirement is the difficult. You don’t want the amount per day but the sum up to that day, for a variable amount of days back. Unfortunatly, mysql does not offer a Sequence (like SELECT numbers from 1 to X) to join with the other parts of the query. If you can live with a restriction to somewhat about 300 years, https://stackoverflow.com/a/9296238/4675841 will help there.
    To get article counts and user counts together, you coult either use union (all) or a join, I used the join and came up with this query.

    SELECT user_query.diff as days_back, article_count as count, user_count as users
    FROM (
        SELECT DATEDIFF(DATE_FORMAT(NOW(),'%Y-%m-%d'), gen_date) as diff, COUNT(create_date) as user_count
        FROM (
            SELECT adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_date
            FROM
                (SELECT 0 t0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
                (SELECT 0 t1 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
                (SELECT 0 t2 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
                (SELECT 0 t3 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
                (SELECT 0 t4 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4) possible_dates
            LEFT JOIN (SELECT DATE_FORMAT(Createdate,'%Y-%m-%d') as create_date FROM tbl_users) counts
                ON create_date <= gen_date
            WHERE gen_date BETWEEN DATE_SUB(NOW(), INTERVAL 20 DAY) AND NOW()
            GROUP BY gen_date) user_query
    INNER JOIN (
        SELECT DATEDIFF(DATE_FORMAT(NOW(),'%Y-%m-%d'), gen_date) as diff, COUNT(create_date) as article_count
        FROM (
            SELECT adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_date
            FROM
                (SELECT 0 t0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
                (SELECT 0 t1 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
                (SELECT 0 t2 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
                (SELECT 0 t3 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
                (SELECT 0 t4 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4) v
            LEFT JOIN (SELECT DATE_FORMAT(Createdate,'%Y-%m-%d') as create_date FROM tbl_articles) counts
                ON create_date <= gen_date
            WHERE gen_date BETWEEN DATE_SUB(NOW(), INTERVAL 20 DAY) AND NOW()
        GROUP BY gen_date) article_query
        ON user_query.diff = article_query.diff
    ORDER BY days_back
    

    Try it out.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search