Count only where certain fields are unique? (Multiple GROUP BYs) - mysql

So I have a query which will count how many records there are for each date in the past 3 days, from my last question with the help of others I was able to come up with the following:
SELECT COUNT(*) AS dailyCount
FROM highscores
WHERE DATE(date) BETWEEN CURDATE() - INTERVAL 3 DAY AND CURDATE()
GROUP BY DATE(date)
The query does the following, for the past 30 days, it will get how many records there are on each individual day and that will be returned as dailyCount.
However what I want to do now is get it so that dailyCount will only count fields where username has not been counted before.
I have tried the following (adding username to the GROUP BYs):
SELECT COUNT(*) AS dailyCount
FROM highscores
WHERE DATE(date) BETWEEN CURDATE() - INTERVAL 3 DAY AND CURDATE()
GROUP BY DATE(date), username
However that did not give the expected result.

Credits to Wrikken
The following worked:
SELECT COUNT(DISTINCT username) AS dailyCount
FROM highscores
WHERE DATE(date) BETWEEN CURDATE() - INTERVAL 3 DAY AND CURDATE()
GROUP BY DATE(date)

Related

Distinct values when already using count and group by

This is currently the SQL query I am using:
SELECT DAY(time), count(id)
FROM users
WHERE time >= now() - INTERVAL 7 DAY
GROUP BY DAY(TIME)
But it includes repeated email values. How can I get the count by day for only unique email address entries?
Thanks
Solution:
SELECT DAY(time), count(distinct email)
FROM userWHERE time >= now() - INTERVAL 7 DAY
GROUP BY DAY(TIME)

SQL Distinct Count from a certain date range?

Have set up a query for my table where I would like to display certain reactions left within the previous weeks period, this works well when I write
SELECT *
FROM reactiondata
WHERE reaction_time > DATE_SUB(NOW(), INTERVAL 1 WEEK)
ORDER BY reaction_time ASC;
And also this query selects the unique promo ID fields and distinct usernames so you can see how many unique usernames have been sent which promo ID.
SELECT
reaction_promoID,
COUNT( DISTINCT reaction_username) AS reaction_username
FROM reactiondata GROUP BY reaction_promoID
However, I would like it so the second query works within a date range for the last week, like the first one does. When I add Where etc... to the query it does not work.
Any help hugely appeciated!
A+TS
SELECT reaction_promoID, COUNT( DISTINCT reaction_username) AS reaction_username
FROM reactiondata
WHERE reaction_time > DATE_SUB(NOW(), INTERVAL 1 WEEK)
GROUP BY reaction_promoID
I think this is time for HAVING clause:
http://www.w3schools.com/sql/sql_having.asp
SELECT reaction_promoID, COUNT( DISTINCT reaction_username) AS reaction_username
FROM reactiondata
GROUP BY reaction_promoID
HAVING reaction_time > DATE_SUB(NOW(), INTERVAL 1 WEEK)

How to count records as "0" that have value "0" when using WHERE x = 1

I have a table structure that looks like this:
I have a perfectly working query that counts how many records there have been per day the last 30 days. It looks likes this:
SELECT DATE(timestamp) AS date, COUNT(id) AS emails FROM 'emails WHERE timestamp >= now() - interval 1 month GROUP BY DATE(timestamp)
This outputs the following which is perfectly fine:
However, the next thing seems too difficult for me to imagine. Now I want to count how many records there have been per day the last 30 days BUT only where newsletter = 1.
I've tried to put a WHERE statement looking like this:
SELECT DATE(timestamp) AS date, COUNT(*) AS emails, nyhedsbrev FROM emails WHERE timestamp >= now() - interval 1 month AND nyhedsbrev = 1 GROUP BY DATE(timestamp)
... And that outputs the following:
The problem is, that its omitting the records with newsletter = 0 and there by I cant compare my first query against the new one, as the dates doesnt match. I know that is because I use WHERE newsletter = 1.
In stead of omitting the record I want a query that just puts a "0" from that date. How can I do this? The final query should be outputting this:
You should be able to simply use SUM() and IF() to get the desired output:
SELECT
DATE(timestamp) AS date,
COUNT(*) AS emails,
SUM(IF(nyhedsbrev > 0, 1, 0)) as nyhedsbrev_count
FROM
emails
WHERE
timestamp >= now() - interval 1 month
GROUP BY
DATE(timestamp)
SQLFiddle DEMO
Edit: You might even be able to simplify it, since it's a boolean, and simply use SUM(nyhedsbrev), but this REQUIRES that nyhedsbrev is only 0 or 1:
SELECT
DATE(timestamp) AS date,
COUNT(*) AS emails,
SUM(nyhedsbrev) as nyhedsbrev_count
FROM
emails
WHERE
timestamp >= now() - interval 1 month
GROUP BY
DATE(timestamp)
Possibly best to get a list of the dates and then left join that against sub queries to get the counts you require.
Something like this
SELECT Sub1.date, Sub2.emails, IFNULL(Sub3.emails, 0)
FROM (SELECT DISTINCT DATE(timestamp) AS date
FROM emails
WHERE timestamp >= now() - interval 1 month) Sub1
LEFT OUTER JOIN (SELECT DATE(timestamp) AS date, COUNT(id) AS emails
FROM emails WHERE timestamp >= now() - interval 1 month
GROUP BY DATE(timestamp)) Sub2
ON Sub2.date = Sub3.date
LEFT OUTER JOIN (SELECT DATE(timestamp) AS date, COUNT(*) AS emails
FROM emails
WHERE timestamp >= now() - interval 1 month AND nyhedsbrev = 1
GROUP BY DATE(timestamp)) Sub3
ON Sub1.date = Sub3.date
(you can probably optimise one subselect of this away, but I have done it in full to make it obvious how it is working)
Assuming newsletter is boolean 1/0 values then this might give you the table that you want:
SELECT DATE(timestamp) AS date, COUNT(*) AS emails, nyhedsbrev
FROM emails WHERE timestamp >= now() - interval 1 month GROUP BY DATE(timestamp),nyhedsbrev ;
Just adding another GROUP BY parameter.

Average posts per hour on MySQL?

I have a number of posts saved into a InnoDB table on MySQL. The table has the columns "id", "date", "user", "content". I wanted to make some statistic graphs, so I ended up using the following query to get the amount of posts per hour of yesterday:
SELECT HOUR(FROM_UNIXTIME(`date`)) AS `hour`, COUNT(date) from fb_posts
WHERE DATE(FROM_UNIXTIME(`date`)) = CURDATE() - INTERVAL 1 DAY GROUP BY hour
This outputs the following data:
I can edit this query to get any day I want. But what I want now is the AVERAGE of each hour of every day, so that if on Day 1 at 00 hours I have 20 posts and on Day 2 at 00 hours I have 40, I want the output to be "30". I'd like to be able to pick date periods as well if it's possible.
Thanks in advance!
You can use a sub-query to group the data by day/hour, then take the average by hour across the sub-query.
Here's an example to give you the average count by hour for the past 7 days:
select the_hour,avg(the_count)
from
(
select date(from_unixtime(`date`)) as the_day,
hour(from_unixtime(`date`)) as the_hour,
count(*) as the_count
from fb_posts
where `date` >= unix_timestamp(current_date() - interval 7 day)
and created_on < unix_timestamp(current_date())
group by the_day,the_hour
) s
group by the_hour
Aggregate the information by date and hour, and then take the average by hour:
select hour, avg(numposts)
from (SELECT date(`date`) as day, HOUR(FROM_UNIXTIME(`date`)) AS `hour`,
count(*) as numposts
from fb_posts
WHERE DATE(FROM_UNIXTIME(`date`)) between <date1> and <date2>
GROUP BY date(`date`), hour
) d
group by hour
order by 1
By the way, I prefer including the explicit order by, since most databases do not order the results of a group by. Mysql happens to be one database that does.
SELECT
HOUR(FROM_UNIXTIME(`date`)) AS `hour`
, COUNT(`id`) \ COUNT(DISTINCT TO_DAYS(`date`)) AS avgHourlyPostCount
FROM fb_posts
WHERE `date` > '2012-01-01' -- your optional date criteria
GROUP BY hour
This gives you a count of all the posts, divided by the number of days, by hour.

Combine two MySQL Count Queries

I have a table with columns: NAME, CHANGE_ID, and CHANGE_DATE, where each row constitutes a single change, the columns indicated who made the change(name), when it was made(timestamp), and an id for the change(integer).
I can retrieve a list of names sorted by those that have made the most changes(in the last month) with the following query:
SELECT
NAME AS name,
COUNT(DISTINCT CHANGE_ID) AS changes
FROM
CHANGE_TABLE
WHERE
DATE(CHANGE_DATE) > DATE(now() - INTERVAL 1 MONTH)
GROUP BY
name
ORDER BY
changes DESC
And I can retrieve a list of changes made per month in the last 10 months with the following query:
SELECT
DATE_FORMAT(CHANGE_DATE, '%Y-%m') AS date,
COUNT(DISTINCT CHANGE_ID) AS change_count
FROM
CHANGE_TABLE
WHERE
CHANGE_DATE > curdate() - INTERVAL 10 MONTH
GROUP BY
date
What I want is a query that will return the combined information of these queries: I want the names of the top change-makers and how many changes they have made each month for the last 10 months. I don't particularly care how the resulting table looks as long as the data is there. I have wracked my brain, but my SQL understanding is not great enough to solve the problem. Any help would be appreciated.
Have you tried grouping on date and name, something like:
SELECT
DATE_FORMAT(CHANGE_DATE, '%Y-%m') AS date,
COUNT(DISTINCT CHANGE_ID) AS change_count,
NAME
FROM
CHANGE_TABLE, (SELECT
NAME AS name,
COUNT(DISTINCT CHANGE_ID) AS changes
FROM CHANGE_TABLE
WHERE DATE(CHANGE_DATE) > DATE(now() - INTERVAL 1 MONTH)
GROUP BY name
ORDER BY changes DESC
) subq
WHERE CHANGE_DATE > curdate() - INTERVAL 10 MONTH AND change_table.name = subq.name
GROUP BY date, name