I want to find the Daily Active Users, which in each application differs how these are calculated. In my case, I have multiple tables where a user could have had an activity.
I've been able to do a LEFT JOIN in one of the tables, but I don't know how to incorporate the rest of the tables to get the activity that happened the last 30 days.
SELECT
DATE_FORMAT(user_video_plays.created_at, '%Y-%m-%d') AS date,
count(*)
FROM
`users`
INNER JOIN `subscriptions` ON `users`.`id` = `subscriptions`.`user_id`
LEFT JOIN `user_video_plays` ON `users`.`id` = `user_video_plays`.`user_id`
WHERE
`users`.`deleted_at` IS NULL
AND `subscriptions`.`chargebee_status` <> 'cancelled'
AND `user_video_plays`.`created_at` BETWEEN '2022-10-01 00:00:00' AND '2022-10-31 23:59:59'
GROUP BY
DATE_FORMAT(user_video_plays.created_at, '%Y-%m-%d')
I have 2 more tables where the user could have activity: forum_posts and forum_post_replies. How can I incorporate them into my query so I get the activity grouped by day?
I've prepared a DB fiddle with the structure and some sample data, as well as my query: https://www.db-fiddle.com/f/ppRaWP7SPDURm8dePyAkEr/0
Thank you
UPDATE 1: Looking at #Luuk answer, I realized that also somehow we need to make this unique. In the following fiddle, I've simplified the data but user_video_plays have 3 plays from the same user and that shouldn't count as 3 but one: https://dbfiddle.uk/ZszSND-H - I think this is easy on my single table query, with a unique, but I should have this into consideration with the 3 extra tables.
I have added forum_posts:
SELECT
DATE_FORMAT(user_video_plays.created_at, '%Y-%m-%d') AS date,
count(*) countUsers,
count(`user_video_plays`.`user_id`) videoPlays,
count(`forum_posts`.`user_id`) forumPosts
FROM
`users`
INNER JOIN `subscriptions` ON `users`.`id` = `subscriptions`.`user_id`
LEFT JOIN `user_video_plays` ON `users`.`id` = `user_video_plays`.`user_id`
AND `user_video_plays`.`created_at` BETWEEN '2022-10-01 00:00:00' AND '2022-10-31 23:59:59'
LEFT JOIN `forum_posts` ON `users`.`id` = `forum_posts`.`user_id`
AND `forum_posts`.`created_at` BETWEEN '2022-10-01 00:00:00' AND '2022-10-31 23:59:59'
WHERE
`users`.`deleted_at` IS NULL
AND `subscriptions`.`chargebee_status` <> 'cancelled'
GROUP BY
DATE_FORMAT(user_video_plays.created_at, '%Y-%m-%d')
NOTE: I moved AND user_video_plays.created_at BETWEEN .... from the WHERE-clause to the ON-clause of the LEFT JOIN.
for the output, see: DBFIDDLE
Can you can do the other table yourself, following this example?
I would like to select all login events and also the number of logins under one specific IP address by a MySQL query.
The Query that I have come up with is as follows. But I am afraid I have been missing something.
Hopefully one can see my mistake.
SELECT `pp_loginevent`.`loginevent_user`,
`pp_loginevent`.`loginevent_creationdate`,
`pp_loginevent`.`loginevent_ip`,
`pp_user`.`user_id`,
`pp_user`.`user_name`,
`pp_user`.`user_rights`,
`pp_user`.`user_active`,
`pp_license`.`license_name`
(SELECT COUNT(1)
FROM `pp_loginevent`
WHERE `loginevent_ip` = `pp_loginevent`.`loginevent_ip`
) AS `pp_loginevent`.`number_of_logins`
FROM `pp_loginevent`
LEFT JOIN `pp_user`
ON `pp_loginevent`.`loginevent_user` = `pp_user`.`user_id
LEFT JOIN `pp_license`
ON `pp_loginevent`.`loginevent_license` = `pp_license`.`license_id`
WHERE `loginevent_creationdate` LIKE '2019-%'
AND `user_rights` <= '6'
GROUP BY `loginevent_ip`
ORDER BY `loginevent_creationdate` DESC
What I am trying to do is to fetch the "column" number_of_logins and that should contain the number of logins made from a specific IP address.
You can't see anything wrong here:
`pp_license`.`license_name`
(SELECT COUNT(1) FROM `pp_loginevent` WHERE `loginevent_ip` = `pp_loginevent`.`loginevent_ip`) AS `pp_loginevent`.`number_of_logins`
?
While this won't resolve all the problems with this query, I think writing the query out this way makes one error very obvious:
SELECT e.loginevent_user
, e.loginevent_creationdate
, e.loginevent_ip
, u.user_id
, u.user_name
, u.user_rights
, u.user_active
, l.license_name
(SELECT COUNT(1)
FROM pp_loginevent
WHERE loginevent_ip = pp_loginevent.loginevent_ip) pp_loginevent.number_of_logins
FROM pp_loginevent e
JOIN pp_user u
ON u.user_id = e.loginevent_user
LEFT
JOIN pp_license l
ON l.license_id = e.loginevent_license
WHERE e.loginevent_creationdate >= '2019-01-01'
AND e.loginevent_creationdate < '2020-01-01'
AND user_rights <= 6
GROUP
BY loginevent_ip
ORDER
BY loginevent_creationdate DESC
In truth, as well as this syntax error, I suspect that there are other, logical, errors in this query.
Accordingly, see: Why should I provide an MCRE for what seems to me to be a very simple SQL query?
I have 2 tables which I want to join and retrieve some specific data. These are my tables.
tbl_user (reg_id, l_name, f_name, status)
tbl_payments (pay_id, reg_id, mem_plan, from_date, to_date, bill_no, payed_date)
What I need to do is select and view the users who have due payments. To do that I want to get the user details where "status=0" from tbl_user and join the 2 tables together and the conditions are to_date< current date, difference between [current date and the to_date] < 31 and filter by the Max value of to_date.
What I did so far gives me a result according to above mentioned conditions except it dosen't filter by the MAX(to_date). This is my query.
SELECT
A.reg_id,
A.f_name,
A.l_name,
B.mem_plan,
B.from_date,
Max(B.to_date) AS to_date,
B.bill_no,
B.payed_date
FROM
tbl_user A,
tbl_payments B
WHERE
A.status = 0
AND A.reg_id = B.reg_id
AND Date(Now()) >= Date(B.to_date)
AND Datediff(Date(Now()), Date(b.to_date)) < 31
GROUP BY
a.reg_id, b.mem_plan, b.from_date, b.bill_no, b.payed_date;
I'm not very familiar with MYSQL, So please someone tell me what I did wrong or if this query is not up to the standard.
Here are some sample data to work on.
tbl_user ( [M1111,Jon, Doe,0], [M1112,Jane,Doe,1],[M1113,Jony,Doe,0] )
tbl_payment ( [1,M1111,Monthly,2018-05-14,2018-06-14,b123,2018-05-14],[2,M1112,3Months,2018-02-03,2018-05-03,b112,2018-02-03],[3,M1113,Monthly,2018-06-14,2018-07-14,b158,2018-06-14],[4,M1111,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[5,M1113,Monthly,2018-06-06,2018-07-06,b158,2018-06-06],[6,M1111,Monthly,2018-07-05,2018-08-05,b345,2018-07-05] )
Assuming current date is 2018-07-17, The expecting result should be this
[M1111,Jon,Doe,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[M1113,Jony,Doe,Monthly,2018-06-14,2018-07-14,b158,2018-06-14]
Instead of that, my query gives me this.
[M1111,Jon,Doe,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[M1113,Jony,Doe,Monthly,2018-06-06,2018-07-06,b158,2018-06-06],
[M1113,Jony,Doe,Monthly,2018-06-14,2018-07-14,b158,2018-06-14]
I wrote another query which gives me the result set exactly as i want. But I'm not sure whether it's up to the standards. If someone can simplify this or make it better, appreciate very much.
SELECT A.reg_id,A.f_name,A.l_name,D.mem_plan,D.from_date,D.to_date,D.bill_no,D.payed_date
FROM tbl_user A
JOIN (SELECT B.reg_id,B.mem_plan,B.from_date,B.to_date,B.bill_no,B.payed_date
FROM tbl_payments B
JOIN (
SELECT reg_id, MAX(to_date) as to_date
FROM tbl_payments
WHERE DATE(NOW()) >= DATE(to_date) AND DATEDIFF(DATE(NOW()), DATE(to_date))<31
GROUP BY reg_id) C
ON B.reg_id = C.reg_id AND B.to_date= C.to_date) D
ON A.reg_id = D.reg_id
WHERE A.status=0;
I believe having won't work here and that your second query is about as good as it gets. I've condensed it a little here:
SELECT A.reg_id,f_name,l_name,mem_plan,from_date,to_date,bill_no,payed_date
FROM #tbl_user A
JOIN #tbl_payments B ON A.reg_id = b.reg_id
JOIN (
SELECT reg_id, MAX(to_date) as max_to_date
FROM #tbl_payments
WHERE DATE(NOW()) >= DATE(to_date) AND DATEDIFF(DATE(NOW()), DATE(to_date))<31
GROUP BY reg_id
) C ON B.reg_id = C.reg_id AND B.to_date= C.max_to_date
WHERE A.status=0;
I have a valid MySQL Query that selects the latest occupancy percentage of a table from each community entered in my DB, but it seems to be scanning the entire DB of entries as the lookup time takes roughly 3-4 seconds.
With the details provided in the query below, can someone provide me with a faster/better way to lookup the latest timestamp field for each community? - I need the query to select every community entered, with the latest timestamp, but the limit for each community selected should be 1 (meaning community named "Test Community" will have possibly hundreds of submissions but I need the latest entered Timestamp selected, along with the same selection for every community entered in the table)
SELECT t1.reportID, t1.communityID, t1.region, t1.percentOccupied,
t1.TIMESTAMP, Communities.fullName
FROM NightlyReports t1
INNER JOIN Communities On t1.communityID = Communities.communityID
WHERE t1.TIMESTAMP = ( SELECT MAX( TIMESTAMP ) FROM NightlyReports WHERE
t1.communityID = NightlyReports.communityID )
AND t1.region = 'GA' ORDER BY percentOccupied DESC
In my experience, correlated subqueries often have rather poor performance; try this instead:
SELECT t1.reportID, t1.communityID, t1.region, t1.percentOccupied
, t1.TIMESTAMP, Communities.fullName
FROM NightlyReports AS t1
INNER JOIN Communities ON t1.communityID = Communities.communityID
INNER JOIN (
SELECT communityID, MAX( TIMESTAMP ) AS lastTimestamp
FROM NightlyReports
WHERE region = 'GA'
GROUP BY communityID
) AS lastReports ON t1.communityID = lastReports.communityID
AND t1.TIMESTAMP = lastReports.lastTimestamp
WHERE t1.region = 'GA'
ORDER BY percentOccupied DESC
Your query is fine. For this query (which is rewritten just a bit):
SELECT nr.reportID, nr.communityID, nr.region, nr.percentOccupied,
nr.TIMESTAMP, c.fullName
FROM NightlyReports nr INNER JOIN
Communities c
ON nr.communityID = c.communityID
WHERE nr.TIMESTAMP = (SELECT MAX(nr2.TIMESTAMP)
FROM NightlyReports nr2
WHERE nr.communityID = nr2.communityID
) AND
nr.region = 'GA'
ORDER BY percentOccupied DESC;
You want indexes on:
NightlyReports(region, timestamp, communityid)
NightlyReports(communityid, timestamp)
Communities(communityID) (this may already exist)
The correlated subquery is not per se a problem.
My host is saying that the following query is taking lots of Server CPU. Please tell me how can I optimize it.
SELECT COUNT(*) FROM (SELECT COUNT(*) AS tot,wallpapers.*,resolutions.res_height,resolutions.res_width FROM wallpapers
INNER JOIN analytics ON analytics.`wall_id` = wallpapers.`wall_id`
INNER JOIN resolutions ON resolutions.`res_id` = wallpapers.`res_id`
WHERE analytics.ana_date >= '2013-09-01 16:36:56' AND wallpapers.wall_status = 'public'
GROUP BY analytics.`wall_id`) as Q
Please note that the analytics table contains the records for all the pageviews and clicks. So it is very very large.
As far as I can tell, your query just counts distinct wall_id values after filtering via the joins and the WHERE clause. Something like this should be close:
SELECT COUNT(DISTINCT analytics.wall_id)
FROM wallpapers
INNER JOIN analytics ON analytics.wall_id = wallpapers.wall_id
INNER JOIN resolutions ON resolutions.res_id = wallpapers.res_id
WHERE analytics.ana_date >= '2013-09-01 16:36:56'
AND wallpapers.wall_status = 'public'
This is your query:
SELECT COUNT(*)
FROM (SELECT COUNT(*) AS tot, wallpapers.*, resolutions.res_height, resolutions.res_width
FROM wallpapers INNER JOIN
analytics
ON analytics.`wall_id` = wallpapers.`wall_id` INNER JOIN
resolutions
ON resolutions.`res_id` = wallpapers.`res_id`
WHERE analytics.ana_date >= '2013-09-01 16:36:56' AND
wallpapers.wall_status = 'public'
GROUP BY analytics.`wall_id`
) as Q
The subquery requires extra effort as does the group by. You can replace this with:
SELECT COUNT(distinct analytics.wall_id)
FROM wallpapers INNER JOIN
analytics
ON analytics.`wall_id` = wallpapers.`wall_id` INNER JOIN
resolutions
ON resolutions.`res_id` = wallpapers.`res_id`
WHERE analytics.ana_date >= '2013-09-01 16:36:56' AND
wallpapers.wall_status = 'public';
You might then be able to do further optimizations using indexes, but it would be helpful to see an explain of this query and the current indexes on the tables.