MYSQL - multiple count statments - mysql

I'm trying to do a lookup on our demographioc table to display some stats. However, since out demographic table is quit big I want to do it in one query.
There are 2 fields that are important: sex, last_login
I want to be able to get the total number of logins for various date ranges (<1day ago, 1-7 days ago, 7-30 days ago, etc) GROUPED BY sex
I right now know how to do it for one date range. For example less than 1 day ago:
SELECT sex, count(*) peeps
FROM player_account_demo
WHERE last_demo_update > 1275868800
GROUP BY sex
Which returns:
sex peeps
----------------
UNKNOWN 22
MALE 43
FEMALE 86
However I'd have to do this once for each range. Is there a way to get all 3 ranges in there?
I'd want my end result to look something like this:
sex peeps<1day peeps1-7days peeps7-30days
Thanks!
IMPORTANT NOTE: last demo_update is the epoch time (unix time stamp)

SELECT sex,
SUM(IF(DATEDIFF(NOW(),last_login) < 1,1,0)),
SUM(IF(DATEDIFF(NOW(),last_login) BETWEEN 1 AND 7,1,0)),
SUM(IF(DATEDIFF(NOW(),last_login) BETWEEN 7 AND 30,1,0))
FROM player_account_demo
GROUP BY sex

You want to use a Pivot Table.

Related

How to Group result from mySQL

My Table:
datetime. employment. name
2019-11-25 12:32:12. office. Michael Jackson
2020-01-31 12:32:22. production. Jenny Darling
2019-12-25 12:32:12. office. Michael Jackson
etc.
This is a "time registering" table, so names must be DISTINCT for each mounth. (How many unique names is there every month grouped by month and employment)
Now i'd like to create a table that will show how many employees there was in every month by year.
So the table will look like:
Year & Month. Employment. Number (Unique names)
-------------------------------------
2019-01. Office. 50
2019-01 Production. 35
2019-02. Office. 45
2019-02. Production. 36
And so on for this and prev year (2019 & 2020)
Something like:
SELECT * FROM table COUNT(DISTINCT(name)) AS number GROUP BY datetime AND employment
You seem to want aggregation... but your query is invalid in several regards. I think you want:
select
date_format(datetime, '%Y-%m') yr_month,
employment,
count(distinct name) no_unique_names
from mytable
group by yr_month, employment
This gives you on row per year/month and employment, with the corresponding count of distinct names.

MySQL: Aggregate weekly statistics with substatics (subqueries)

I would like to gather weekly statics on a MySQL-Table.
The table itself has the following structure:
user_id action_id created
0 123 2017-01-01 00.00:00
0 124 ...
1 123 ...
... ... ...
I would like to aggregate the weekly statics for:
How many user where active per week
This is rather simple:
SELECT
YEARWEEK(created) as week,
COUNT(DISTINCT user_id) AS count
FROM data
GROUP BY YEARWEEK(created);
Additionally I could apply a sorting.
The result looks like:
week count
201701 2
201702 3
How many user where active per week for the very first time
I thought about solving it by using a subquery
SELECT
YEARWEEK(created) as week,
COUNT(DISTINCT user_id) AS count,
(
SELECT
COUNT(DISTINCT d2.user_id)
FROM data d2
WHERE YEARWEEK(d2.created) = week
AND NOT EXISTS (SELECT 1 FROM data d3
WHERE YEARWEEK(d3.created) < week AND d2.user_id = d3.user_id)
) as countNewUsers
FROM data d1
GROUP BY YEARWEEK(created);
How many junior user where active per week
Junior users were active between 1 and 10 times before the related week
Similar to the one above, but with other subquery
How many power user where active per week
Senior users were active more than 10 times before the related week
This works as expected, but has a rather poor performance, since the subquery is evaluated before the grouping happens. With millions of rows in a table, this takes ages.
Does anybody have a better solution for this query, ideally returning all values in single result set?
I think all of your queries could derive from one 'intermediate' table. It would contain (yearweek, userid, count).
Users active per week: Pretty much the same query, but faster from this table.
Active for first time: Self-join ON userid and desired week versus MIN(yearweek)
Uses before the target week: ... SUM(count) WHERE ... < week GROUP BY userid
Use the above to determine which userids of Junior/Power.

GROUP BY date and sum together forward yes but backward no

I have a table
PEOPLE, DATE, DELETED
Amanda, 2015-03-01, Null
Ray, 2015-03-01, Null
Moe, 2015-04-01, Null
Yan, 2015-05-01, Null
Bee, 2015-05-05, 2015-06-12
now I need to group it and sum it with months like this:
March: 2 people
April: 3
May: 5
June: 5
July: 4
so new people should not be counted in previous month but they should be in next months for my range (January - June). And if man is DELETED, he should be counted together with another people last time in month when he has been deleted.
How to write query for this?
This can be at least solved using running totals. This just the outline how to do it, you'll need to do some work for the actual solution:
select people, date, 1 as persons from yourtable
union all
select people, deleted, -1 as persons from yourtable where deleted is not null
Then do a running total of this data, so that you sum the +-1 persons -field, and that should give you the amount of people that are there so far.
For the events happening in the middle of the month, you'll have to adjust the date to be the start of that or the next month whichever way you want them to be calculated.
If you need also those months when no changes happened, you'll probably need a table that contains the first day of each month for the biggest range of dates you'll ever need, for example 1.1.2000 - 1.12.2100.

Number of rows returned when adding before/after date logically inconsistant

I have a database containing information about a students visit to our tutoring center. Each time a student visits a record is produced which includes their names, their student number the date they visited, what they were there for and how long they were there.
We create new tables for each term
I was asked to get an unduplicated count of how many students were there during a certain term so I run the following.
SELECT * FROM `tutoringdata_201350` group by `anum`
anum being the students unique identification number, which returns 524 results out of 5525 total records. In theory that should be my unduplicated count.
I was then asked to get records before and after a certain date in that same table, so I run.
SELECT * FROM `tutoringdata_201350` WHERE `cDate` <= "09/30/2013" group by `anum`
Which works, so far as the date is concerned and no duplicate people are returned so far as I can see in the results window if I sort by the anumber they are all unique. BUT the total number of results returned is 375
So to get students after that date I run
SELECT * FROM `tutoringdata_201350` WHERE `cDate` > "09/30/2013" group by `anum`
which also appears to work, no duplicated students in the returned results but total number of returned results is 428.
375 + 428 is 803 not 524 which I would expect. I'm having trouble following the logic, which of the 2 different types of queries are producing an inaccurate number of results.
You are misusing the pernicious nonstandard MySQL extension to GROUP BY. http://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html
You probably want something like this;
SELECT COUNT(DISTINCT anum) unique_students
FROM `tutoringdata_201350`
WHERE cDate <= 'whatever'
You could also do this to find out how many visits each student made.
SELECT COUNT(*) visits,
anum
FROM `tutoringdata_201350`
WHERE cDate <= 'whatever'
GROUP BY anum
You are also, I think, making a mistake in the way you are comparing dates.
MySQL uses an internal DATE and DATETIME format. If you want to compare such data items in your table to a text-string constant, you need to use the correct format -- YYYY-MM-DD -- for that string. For example:
WHERE cDate <= '2013-09-30'
The comparison in your example isn't correct. Edit. If your dates are stored as text strings as MM/DD/YYYY, you need to use the following sort of comparison.
WHERE STR_TO_DATE(cDate, '%m/%d/%Y') <= '2013-09-30'
This will convert your legacy date strings to DATE format. Then the comparison will work. If you don't do this MySQL is just comparing strings to strings. (You may, or may not, luck out if the years don't vary.)
Now, your counts of unique students before and after the first of October do not necessarily sum up to the count of unique students for the whole term. Here's an example.
Joe Sept 28
Joe Sept 29
Mary Sept 30
Henry Sept 30
Joe Oct 1
Stephen Oct 1
Overall there are four distinct students. In Sept there are three. In October there are two. If you add those two numbers you get five. That's more because you're double-counting Joe by adding those two numbers.

Group results by period

I have some data which I want to retrieve, but I want to have it grouped by a specific number of seconds. For example if my table looks like this:
| id | user | pass | created |
The created column is INT and holds a timestamp (number of seconds from 1970).
I would want the number of users that are created between last month and the current date, but show them grouped by let's say 7*24*3600 (a week). So if in the range there are 1000 new users, have them show up how many registered each week (100 the first week, 450 the second, 50 the third and 400 the 4th week -- something like this).
I've tried grouping the results by created / 7*24*3600, but that's not working.
How should my query look like?
You need to use integer division div otherwise the result will turn into a real and none of the weeks will resolve to the same value.
SELECT
(created div (7*24*60*60)) as weeknumber
, count(*) as NewUserCount
FROM users
WHERE weeknumber > 1
GROUP BY weeknumber
See: http://dev.mysql.com/doc/refman/5.0/en/arithmetic-functions.html
You've got to keep the integer part only of that division. You can do it with the floor() function.
Have you tried select floor(created/604800) as week_no, count(*) from users group by floor(created/604800) ?
I assume you've got the "select users created in the last month" part sorted out.
Okay here are the possible options you may try:
GROUP BY DAY
select count(*), DATE_FORMAT(created_at,"%Y-%m-%d") as created_day FROM widgets GROUP BY created_day
GROUP BY MONTH
select count(*), DATE_FORMAT(created_at,"%Y-%m") as created_month FROM widgets GROUP BY created_month
GROUP BY YEAR
select count(*), DATE_FORMAT(created_at,"%Y") as created_year FROM widgets GROUP BY created_year