User Activity Report using Calendar Table - mysql

I am driving nuts to get what it was supposed to be a simple query done. I have the following table:
Daily Check-In Table: tbl_checkin (uniqueid, userid, clock)
Sample data:
1 1 7/25/2014 12:00:00 AM
2 1 7/25/2014 2:37:05 PM
3 2 7/25/2014 3:22:29 PM
Calendar Table: calendar (datefield)
Sample data contains dates from 2012 to 2050 (i.e. 1/1/2012 12:00:00 AM, etc..)
I am looking to get this result:
Date: Count:
Jul 21 0
Jul 22 0
Jul 23 0
Jul 24 0
Jul 25 3
Jul 26 0
Jul 27 0
Jul 28 0
My query specifies a date range. In the above sample, I specified 1 week but I could specified any date range. The closest I got with the query is this:
SELECT
date_format(calendar.datefield, '%b %e') AS clockdate,
COUNT(*) AS total
FROM tbl_checkin RIGHT JOIN calendar ON (DATE(tbl_checkin.clock) = calendar.datefield)
WHERE (calendar.datefield BETWEEN (SELECT MIN(DATE('2014-07-21')) FROM tbl_checkin)
AND (SELECT MAX(DATE('2014-07-28')) FROM tbl_checkin))
GROUP BY clockdate;
The result I get is this:
Date: Count:
Jul 21 1
Jul 22 1
Jul 23 1
Jul 24 1
Jul 25 3
Jul 26 1
Jul 27 1
Jul 28 1
For some reason I get 1 on the dates I have nothing. A user could have multiple entries in a single day. Does anyone see what I am doing wrong? Thanks a lot.

When count(*) is used, rows where tbl_checkin.clock is null is also counted as 1 (because of the right join). We just need to replace count(*) with count(tbl_checkin.clock):
SELECT
date_format(calendar.datefield, '%b %e') AS clockdate,
COUNT(tbl_checkin.clock) AS total
FROM tbl_checkin
RIGHT JOIN calendar ON DATE(tbl_checkin.clock) = calendar.datefield
WHERE calendar.datefield BETWEEN '2014-07-21' AND '2014-07-28'
GROUP BY clockdate;

Related

Select unique combination from a table in Mysql

My dataset has the following format;
Student_id Month Year Amount
1 Jan 2010 600
1 Feb 2010 391
1 Apr 2010 673
1 Jul 2010 564
5 Jan 2010 789
5 Mar 2011 298
5 Aug 2010 347
7 Jan 2010 654
7 Dec 2011 621
7 Apr 2010 450
7 Nov 2011 980
... & so on.
I wish my output which will have max amount for each unique id-month-year combination. Viz,
Student_id Month Year Amount
1 Apr 2010 673
5 Jan 2010 789
7 Nov 2011 980
... & like this.
How to get the output using SQL? I tried
select distinct * , MAX(Amount) from student_details;
&
SELECT *, MAX(Amount)
FROM student_details
WHERE Amount IN
(
FROM student_details
GROUP BY Student_ID, Year, Month
);
but the output is not as desired.
Please suggest assistance. Thanks in advance.
In MySQL:
SELECT t0.*
FROM student_details AS t0
LEFT JOIN student_details AS t1 ON t0.Student_id=t1.Student_id t1.Amount>t0.Amount
WHERE t1.Student_id IS NULL;
In SQL server:
SELECT T.Student_id,T.Month,T.Year,T.Amount
FROM
(
SELECT *,row_number() over (PARTITION BY Student_ID ORDER BY Amount DESC) as RN
FROM student_details
)T
WHERE T.RN=1
Simply use below query
first select amount month for each user then select data which has selected month
SELECT * FROM table WHERE amount IN (
SELECT max(amount) FROM table group by student_id
)

Incremental counts in mysql

I have a table "UserLogins" and when the user login into the system I will drop a record in the "UserLogins" table.
Jan 10th (Users : 1,2,3,4) // four records with Ids 1,2,3,4
Jan 20th (1,2,3,4,5,6) // six records with Ids 1,2,3,4,5,6
Jan 30th (1,2)
Feb 10th (1,7)
Feb 20th (2,6,8)
Feb 25th (1,2,3,5)
Mar 10th (3,4)
Mar 20th (4,5,9)
Mar 30th (8,10,11)
Apr 10th (10,12)
Apr 20th (1,2,3,6,13, 14, 15)
Apr 30th (11,12,16)
When I write the group by my results as follows
Jan - 6
Feb - 7
Mar - 7
Apr - 11
But I need an out put like as follows
Upto Jan - 6 //count of distinct users upto Jan
Upto Feb - 8 //count of distinct users upto Feb
Upto Mar - 11 //count of distinct users upto Mar
Upto Apr - 16 //count of distinct users upto Apr
Your first count could simply be like this:
SELECT
DATE_FORMAT(login_date, '%Y-%b') AS year_month,
COUNT(DISTINCT user_id)
FROM
UserLogins
GROUP BY
DATE_FORMAT(login_date, '%Y-%b')
while to count all users up to a given mount, I would use a Join:
SELECT
DATE_FORMAT(last_day, '%Y-%b') AS year_month,
COUNT(DISTINCT user_id)
FROM
(SELECT DISTINCT LAST_DAY(login_date) as last_day
FROM UserLogins) d
INNER JOIN
UserLogins ON UserLogins.login_date<=last_day
GROUP BY
DATE_FORMAT(last_day, '%Y-%b')
on the subquery d I will return all last days of every month that has a record on the UserLogins table, then I will join all userlogin that logged up to the end of the month, and then I will do the count.

Group by month and return 0 if data not found

I have been trying to fix my query for days now :(.
It is supposed to group by month and return 0 if record is not found.
An example:
SELECT MONTH(created_at) AS month_num,
DATE_FORMAT(created_at, '%b') AS month_name, COUNT(*) AS total_num
FROM table WHERE user_id=1384249399168
GROUP BY MONTH(created_at) ORDER BY created_at DESC
Result:
month_num month_name total_num
8 Aug 20
7 Jul 15
5 May 39
2 Feb 10
1 Jan 8
Espected Result:
month_num month_name total_num
12 Dec 0
11 Nov 0
10 Oct 0
9 Sep 0
8 Aug 20
7 Jul 15
6 Jun 0
5 May 39
4 Apr 0
3 Mar 0
2 Feb 10
1 Jan 8
I have tried a lot of answers especially this MySql count() to return 0 if no records found but without success.
Any help please?
I haven't tested but it should work:
SELECT MONTH(created_at) AS month_num,
DATE_FORMAT(created_at, '%b') AS month_name, ifnull(count(*),0) AS total_num
FROM table WHERE user_id=1384249399168
GROUP BY MONTH(created_at) ORDER BY created_at DESC
This post solved my problem.
I had to create a table which contains all the 12 months.
mysql select the count of records for every month
Thanks anyone especially #Turdaliev

Finding AVG value in SQL Query after SUM - Invalid use of group function

I have some query which works fine for me:
Select Name,sum(number_hours)/8)*100
from
T1
where name='PERSON_A'
group by name,booked_date
Name is always ONE same person which I put in where clause.Result will be:
PERSON_A 100
PERSON_A 140
PERSON_A 120
This is calculating some daily utilization for workers for each booked date.
Now I want to calculate AVERAGE daily utilization((120+120+100)/3=120)
But when I put
Select Name,AVG(sum(number_hours)/8)*100)
FROM
T1
WHERE name='PERSON_A'
group by name,booked_date
I am getting error Invalid use of group function. Why? How can I calculate average value after summuryzing values for daily utilization.
Thanks
Try using a subquery for the sum and calculate the average in the outer query, like in:
SELECT Name, AVG (hsum)
FROM
(
SELECT Name,sum((number_hours)/8)*100 AS hsum
FROM
T1
WHERE name='PERSON_A'
GROUP BY name,booked_date
) t
I understand you already have accepted the answer. But give this a try too :) No subquery. Quite fast too. I added extra Count of workdates column for you to see the dates.
* SQLFIDDLE DEMO
Sample data table:
ID NAME HOURS WORKDATE
100 j 20 December, 03 2012 00:00:00+0000
200 k 10 December, 03 2012 00:00:00+0000
100 j 10 December, 04 2012 00:00:00+0000
300 l 20 December, 04 2012 00:00:00+0000
100 j 5 December, 05 2012 00:00:00+0000
300 l 15 December, 03 2012 00:00:00+0000
100 j 10 December, 04 2012 00:00:00+0000
400 m 20 December, 03 2012 00:00:00+0000
Query:
SELECT Name, ((sum(hours)/8)*100) AS sum
,count(distinct workdate) workdates, ((sum(hours)/8)*100)/count(
distinct workdate) as avg
FROM
works
WHERE name='j'
GROUP BY name
;
Results:
NAME SUM WORKDATES AVG
j 562.5 3 187.5

Table Date column comparison with a generated dates list - MYSQL

There seem to be a weird behaviour when comparing a date in table column with a date generated in a list within MYSQL.
Please take a look at the * SQLFIDDLE reference.
Payroll Table:
ID DATESTAMP
1 August, 30 2012 00:00:00+0000
2 September, 02 2012 00:00:00+0000
3 September, 15 2012 00:00:00+0000
4 September, 24 2012 00:00:00+0000
5 October, 05 2012 00:00:00+0000
6 October, 16 2012 00:00:00+0000
7 October, 19 2012 00:00:00+0000
8 November, 02 2012 00:00:00+0000
9 November, 10 2012 00:00:00+0000
10 November, 16 2012 00:00:00+0000
11 November, 24 2012 00:00:00+0000
12 November, 30 2012 00:00:00+0000
13 December, 01 2012 00:00:00+0000
14 December, 07 2012 00:00:00+0000
Dates list is generated between two particular dates with a constant day interval
Query:
set #i:= 0;
SELECT date_format(DATE(ADDDATE('2012-10-05',
INTERVAL #i:=#i+14 DAY)),'%Y-%m-%d')
AS dateP, #i
FROM payroll
HAVING #i < datediff(now(), date '2012-10-05')
;
DATEP #IntervalDays
2012-10-19 14
2012-11-02 28
2012-11-16 42
2012-11-30 56
2012-12-14 70
As you can see the generated dates list has matches to the Payroll table above. However when the comparison is done, it reutns zero records.
Comparison Query:
set #i:= 0;
SELECT distinct datestamp FROM payroll
WHERE date(datestamp) in (
SELECT DATE(ADDDATE('2012-10-05',
INTERVAL #i:=#i+14 DAY) ) AS dateP
FROM payroll
where #i < DATEDIFF(now(), date '2012-10-05')
)
;
So Questions I have:
Is the inner query stop generating dates when used as a nested query?
Is there anything wrong with the dates comparison method I am using here?
What could be the reason for this entire failure?
How to fix it within Select itself without any procedure/functions? :)
PS:
I am also trying to test this in SQL server as well as Oracle.
There are many good questions and answers to support 'Date Comparison' issues occurred at various scenarios with the site. That includes posts such as mysql date comparison with date_format. etc.. May be there's one hidden somewhere asking for exact issue I am facing with different wording. Couldn't find and hence posted the question.
Second UPDATE:
Now I got it working in every version:
select
*
from
Payroll
inner join
(
SELECT DATE(DATE_ADD('2012-10-05',
INTERVAL #i:=#i+14 DAY) ) AS dateP
FROM Payroll, (SELECT #i:=0) r
where #i < DATEDIFF(now(), date '2012-10-05')
) sq on Payroll.datestamp = sq.dateP
You just have to initialize the variable inside the query.
UPDATE:
Strange thing is, this one works on my local machine without problems (version 5.1.41-3ubuntu12.7-log), but not in your SQLfiddle.
set #i:= 0;
select
*
from
Payroll
inner join
(
SELECT DATE(DATE_ADD('2012-10-05',
INTERVAL #i:=#i+14 DAY) ) AS dateP
FROM Payroll
where #i < DATEDIFF(now(), date '2012-10-05')
) sq on Payroll.datestamp = sq.dateP
END OF UPDATE
Have you tried it like this?
set #i:= 0;
SELECT distinct datestamp FROM payroll
WHERE STR_TO_DATE(datestamp, '%M, %d %Y %H:%i:%f') in (
SELECT DATE(ADDDATE('2012-10-05',
INTERVAL #i:=#i+14 DAY) ) AS dateP
FROM payroll
where #i < DATEDIFF(now(), date '2012-10-05')
)
;
My guess is, that the DATE() function fails, cause you're varchar(is it?) date is not in ISO format. Therefore you have to use STR_TO_DATE() function.
For exact usage of STR_TO_DATE() read here and here. I'm not sure about the microsecond part.