I have a table that logs various transactions for a CMS. It logs the username, action, and time. I have made the following query to tell me how many transactions each user made in the past two days, but it is so slow its faster for me to send a bunch of separate querys at this point. Am I missing a fundamental rule for writing nested queries?
SELECT DISTINCT
`username`
, ( SELECT COUNT(*)
FROM `ActivityLog`
WHERE `username`=`top`.`username`
AND `time` > CURRENT_TIMESTAMP - INTERVAL 2 DAY
) as `count`
FROM `ActivityLog` as `top`
WHERE 1;
You could use:
SELECT username
, COUNT(*) AS count
FROM ActivityLog
WHERE time > CURRENT_TIMESTAMP - INTERVAL 2 DAY
GROUP BY username
An index on (username, time) would be helpful regarding speed.
If you want users with 0 transcations (the last 2 days), use this:
SELECT DISTINCT
act.username
, COALESCE(grp.cnt, 0) AS cnt
FROM ActivityLog act
LEFT JOIN
( SELECT username
, COUNT(*) AS count
FROM ActivityLog
WHERE time > CURRENT_TIMESTAMP - INTERVAL 2 DAY
GROUP BY username
) AS grp
ON grp.username = act.username
or, if you have a users table:
SELECT
u.username
, COALESCE(grp.cnt, 0) AS cnt
FROM users u
LEFT JOIN
( SELECT username
, COUNT(*) AS count
FROM ActivityLog
WHERE time > CURRENT_TIMESTAMP - INTERVAL 2 DAY
GROUP BY username
) AS grp
ON grp.username = u.username
Another way, similar to yours, would be:
SELECT username
, SUM(IF(time > CURRENT_TIMESTAMP - INTERVAL 2 DAY, 1, 0))
AS count
FROM ActivityLog
GROUP BY username
or even this (because true=1 and false=0 for MySQL):
SELECT username
, SUM(time > CURRENT_TIMESTAMP - INTERVAL 2 DAY)
AS count
FROM ActivityLog
GROUP BY username
No need for nesting...
SELECT `username`, COUNT(`username`) as `count` FROM `ActivityLog` WHERE `time` > CURRENT_TIMESTAMP - INTERVAL 2 DAY GROUP BY `username`
Also don't forget to add an INDEX on time if you want to make it even faster
Related
I have this query i use to get statistics of blogs in our own tracking system.
I use union select over 2 tables as we daily aggregate data in 1 table and keeps todays data in another table.
I want to have the last 10 months of traffic show.. This query does that, but of there is no traffic in a specific month that row is not in the result.
I have previously used a calendar table in mysql to join against to at avoid that, but im simply not skilled enoght to rewrite this query to join against that calendar table.
The calendart table has 1 field called "datefield" which i date format YYY-MM-DD
This is the current query i use
SELECT FORMAT(SUM(`count`),0) as `count`, DATE(`date`) as `date`
FROM
(
SELECT count(distinct(uniq_id)) as `count`, `timestamp` as `date`
FROM tracking
WHERE `timestamp` > now() - INTERVAL 1 DAY AND target_bid = 92
group by `datestamp`
UNION ALL
select sum(`count`),`datestamp` as `date`
from aggregate_visits
where `datestamp` > now() - interval 10 month
and target_bid = 92
group by `datestamp`
) a
GROUP BY MONTH(date)
Something like this?
select sum(COALESCE(t.`count`,0)),s.date as `date`
from DateTable s
LEFT JOIN (SELECT * FROM aggregate_visits
where `datestamp` > now() - interval 10 month
and target_bid = 92) t
ON(s.date = t.datestamp)
group by s.date
I have a table, that pretty much looks like this:
users (id INT, masterId INT, date DATETIME)
Every user has exactly one master. But masters can have n users.
Now I want to find out how many users each master has. I'm doing that this way:
SELECT `masterId`, COUNT(`id`) AS `total` FROM `users` GROUP BY `masterId` ORDER BY `total` DESC
But now I also want to know how many new users a master has since the last 14 days. I could do it with this query:
SELECT `masterId`, COUNT(`id`) AS `last14days` FROM `users` WHERE `date` > DATE_SUB(NOW(), INTERVAL 14 DAY) GROUP BY `masterId` ORDER BY `total` DESC
Now the question: Could I somehow get this information with one query, instead of using 2 queries?
You can use conditional aggregation to do this by only counting rows for with the condition is true. In standard SQL this would be done using a case expression inside the aggregate function:
SELECT
masterId,
COUNT(id) AS total,
SUM(CASE WHEN date > DATE_SUB(NOW(), INTERVAL 14 DAY) THEN 1 ELSE 0 END) AS last14days
FROM users
GROUP BY masterId
ORDER BY total DESC
Sample SQL Fiddle
I have a table
id user Visitor timestamp
13 username abc 2014-01-16 15:01:44
I have to 'Count' total visitors for a 'User' for last seven days group by date(not timestamp)
SELECT count(*) from tableA WHERE user=username GROUPBY __How to do it__ LIMIT for last seven day from today.
If any day no visitor came so, no row would be there so it should show 0.
What would be correct QUERY?
There is no need to GROUP BY resultset, you need to count visits for a week (with unspecified user). Try this:
SELECT
COUNT(*)
FROM
`table`
WHERE
`timestamp` >= (NOW() - INTERVAL 7 DAY);
If you need to track visits for a specified user, then try this:
SELECT
DATE(`timestamp`) as `date`,
COUNT(*) as `count`
FROM
`table`
WHERE
(`timestamp` >= (NOW() - INTERVAL 7 DAY))
AND
(`user` = 'username')
GROUP BY
`date`;
MySQL DATE() function reference.
Try this:
SELECT DATE(a.timestamp), COUNT(*)
FROM tableA a
WHERE a.user='username' AND DATEDIFF(NOW(), DATE(a.timestamp)) <= 7
GROUP BY DATE(a.timestamp);
i think it's work :)
SELECT Count(*)
from table A
WHERE user = username AND DATEDIFF(NOW(),timestamp)<=7
I have a table with: userid and timestamp each time a user opens a page a new field is inserted.
I am trying to get the total amount of hours / minutes / days / weeks that appear in a 1 month interval for multiple users.
I have tried a bunch of different queries but each have ended up terribly inefficient.
Ideally I'd like to end up with something like:
userid | minutes | hours | days | weeks
1 10080 168 7 1
2 1440 24 1 0
Hopefully someone can shed some light on how to do this.
Below is a query that I tried:
SELECT
w.time AS `week`,
d.time AS `day`,
h.time AS `hour`,
m.time AS `minutes`
FROM (
SELECT
SUM( t.time ) AS `time`
FROM (
SELECT
COUNT( DISTINCT WEEK( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY MONTH( `timestamp` )
) t
) w,
(
SELECT
SUM( t.time ) AS `time`
FROM (
SELECT
COUNT( DISTINCT DAY( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "52"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY MONTH( `timestamp` )
) t
) d,
(
SELECT
SUM( t.timestamp ) AS `time`
FROM (
SELECT
COUNT( DISTINCT HOUR( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY DAY( `timestamp` )
) t
) h,
(
SELECT
SUM( t.timestamp ) AS `time`
FROM (
SELECT
COUNT( DISTINCT MINUTE( `timestamp` ) ) AS `time`
FROM table
WHERE
userid = "1"
AND
`timestamp` > DATE_SUB( NOW( ) , INTERVAL 1 MONTH )
GROUP BY HOUR( `timestamp` )
) t
) m
It seems awfully excessive for this task, maybe someone has something better?
It's not clear to me what you want to "total".
If you want to determine whether a user had a "hit" (or whatever transaction it is you are storing in the table) at any given minute within the month), and then you want to count the number of "minute periods" within a month that a user had a hit:
SELECT t.userid
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d %H:%i')) AS minutes
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d %H' )) AS hours
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%Y-%m-%d' )) AS days
, COUNT(DISTINCT DATE_FORMAT(t.timestamp,'%X-%V' )) AS weeks
FROM mytable t
WHERE t.timestamp >= '2012-06-01'
AND t.timestamp < '2012=07-01'
GROUP BY t.userid
What this is doing is taking each timestamp, and putting it into a "bucket", by chopping off the seconds, chopping off the minutes, chopping off the time, etc.
Basically, we're taking a timestamp (e.g. '2012-07-25 23:15:30') and assigning it to
minute '2012-07-25 23:15'
hour '2012-07-25 23'
day '2012-07-25'
A timestamp of '2012-07-25 23:25:00' would get assigned to
minute '2012-07-25 23:25'
hour '2012-07-25 23'
day '2012-07-25'
Then we go through and count the number of distinct buckets we assigned a timestamp to. If that's all the hits for this user in the month, the query would return a 2 for minutes, and a 1 for all other period counts.
For a user with a single hit within the month, all the counts for that user will be a 1.
For a user that has all their "hits" within exactly the same minute, the query will again return a 1 for all the counts.
(For a user with no "hits" within a month, no row will be returned. (You'd need to join another row source to get a list of users, if you wanted to return zero counts.)
For a user with a "hit" every second within a single day, this query will return counts like that shown for userid 2 in your example.
This result set gives you a kind of an indication of a user's activity for a month... how many "minute periods" within a month the user was active.
The largest value that could be returned for "days" would be the number of days in the month. The largest possible value to be returned for "hours" would be 24 times the number of days in the month times. The largest possible value returned for "minutes" would be 1440 times the number of days in the month.
But again, it's not entirely clear to me what result set you want to return. But this seems like a much more reasonable result set than the one from the previously "selected" answer.
SELECT userid, SUM(MINUTE(timestamp)) AS minutes, SUM(MINUTE(timestamp))/60 AS hours, SUM(MINUTE(timestamp))/(60*24) AS days, SUM(MINUTE(timestamp))/(60*24*7) AS weeks
FROM Table
GROUP BY userid
If neccesary, use ROUND(SUM(MINUTE(timestamp)), 0) if you want integer numbers.
I'm trying to collect the number of distinct visits in my cp yesterday, then count them.
SELECT
DISTINCT `user_id` as user,
`site_id` as site,
`ts` as time
FROM
`cp_visits`
WHERE
ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
For some reason this is pulling multiple results with the same site id....how do i only pull and count the distinct site_id cp logins?
Select
Count(Distinct user_id) As countUsers
, Count(site_id) As countVisits
, site_id As site
From cp_visits
Where ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
Group By site_id
Overall
SELECT
COUNT(DISTINCT `site_id`) as distinct_sites
FROM `cp_visits`
WHERE ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
Or per site
SELECT
`site_id` as site,
COUNT(DISTINCT `user_id`) as distinct_users_per_site
FROM `cp_visits`
WHERE ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY `site_id`
Having the time column in the result doesn't make sense - since you are aggregating the rows, showing one particular time is irrelevant, unless it is the min or max you are after.
You need to use a group by clause.
SELECT site_id, MAX(ts) as TIME, count(*) group by site_id