I have a table that looks like this:
ID t_stamp views uviews hits uhits
1 7/18/2012 19:00 105 11 0 0
5 7/18/2012 20:00 1 1 0 0
2 7/19/2012 9:00 118 4 0 0
1 7/19/2012 10:00 196 18 0 0
7 7/19/2012 11:00 2 1 0 0
2 7/19/2012 12:00 38 11 0 0
2 7/19/2012 13:00 20 5 0 0
2 7/19/2012 19:00 9 2 0 0
2 7/20/2012 15:00 85 6 0 0
1 7/20/2012 16:00 483 101 2 2
2 7/20/2012 17:00 1200 240 0 0
2 7/20/2012 18:00 1200 232 0 0
2 7/20/2012 19:00 1199 231 0 0
2 7/20/2012 20:00 1200 236 0 0
2 7/20/2012 21:00 1201 237 0 0
1 7/20/2012 22:00 1220 187 0 0
1 7/20/2012 23:00 869 165 0 0
And my method is to combine them by the day so I can get a SUM for each of the last four columns. The IDs do not really matter.
I am using this:
SELECT `bannerID` , DATE_FORMAT( `t_stamp` , '%m/%d/%Y' ) AS `date` ,
SUM( `views` ) AS `views` , SUM( `uviews` ) AS `uviews` , SUM( `hits` ) AS `hits` , SUM( `uhits` ) AS `uhits`
FROM test_bannerstats
WHERE DATE( t_stamp ) >= DATE( '2012-07-01' )
AND DATE( t_stamp ) <= DATE( '2012-08-24' )
GROUP BY `date`
ORDER BY `date` ASC
However that doesn't seem correct to me as that the numbers seem conflicting. In the end I want to get a daily tally the last four columns by day.
EDIT:
It is a problem with time zones it looks! I will show you why...
Look at the table above, now let's do the additions for the entire day...
1 07/18/2012 106 12 0 0
1 07/19/2012 383 41 0 0
1 07/20/2012 8657 1635 2 2
Above is correct. Below is wrong.
1 07/18/2012 105 11 0 0
1 07/19/2012 384 42 0 0
1 07/20/2012 4167 810 2 2
The problem? Anything after 8pm is going to the next day. It is a timezone issue that I have to sort out it seems.
Your query can be simplified as:
SELECT `bannerID`,
DATE_FORMAT( `t_stamp` , '%m/%d/%Y' ) AS `date`,
SUM( `views` ) AS `views`,
SUM( `uviews` ) AS `uviews`,
SUM( `hits` ) AS `hits`,
SUM( `uhits` ) AS `uhits`
FROM test_bannerstats
WHERE DATE( t_stamp ) BETWEEN '2012-07-01' AND '2012-08-24'
GROUP BY DATE(t_stamp)
ORDER BY DATE(t_stamp) ASC;
try this one,
SELECT DATE_FORMAT(DATE(t_stamp), '%m/%d/%Y') AS `date`,
SUM(views) totalViews,
SUM(uviews) totalUViews,
SUM(hits) totalHits,
SUM(uhits) totalUHits,
FROM tableName
WHERE DATE( t_stamp ) >= DATE( '2012-07-01' ) AND
DATE( t_stamp ) <= DATE( '2012-08-24' )
GROUP BY DATE(t_stamp)
ORDER BY `date` ASC
I think you're sql query wont really work, that is only applicable for date july 1 to august 24. What if the last 4 date is beyond that date? It wont pick up anything.
In my opinion the best way to do it is this:
SELECT SUM(column_name) FROM table_name order by id DESC limit 4;
Order by ID desc will sort the results in descending order. Limit 4, will only pick up the first 4 results.
Hope that helps.
If you want to give your indexes a chance to be used, avoid using functions on columns when you can. Replace the conditions:
WHERE DATE( t_stamp ) >= DATE( '2012-07-01' )
AND DATE( t_stamp ) <= DATE( '2012-08-24' )`
with:
WHERE t_stamp >= DATE( '2012-07-01' )
AND t_stamp < DATE( '2012-08-25' )
You define the alias date in the SELECT list. This alias cannot be used in the WHERE or GROUP BY clauses (to be honest, it can be used at the GROUP BY clause but I wouldn't recommend it). Instead of:
GROUP BY `date`
use:
GROUP BY DATE(t_stamp)
There is a proprietary MySQL syntax available (you can read it at the SELECT documenation) when the GROUP BY and ORDER BY are done on the same expression. Instead of:
GROUP BY DATE(t_stamp)
ORDER BY DATE(t_stamp) ASC;
you can use (for a slight efficiency gain):
GROUP BY DATE( t_stamp ) ASC ;
The query becomes now:
SELECT
bannerID
, DATE_FORMAT( DATE( t_stamp ), '%m/%d/%Y' ) AS `date`
, SUM( views ) AS views
, SUM( uviews ) AS uviews
, SUM( hits ) AS hits
, SUM( uhits ) AS uhits
FROM
test_bannerstats
WHERE
t_stamp >= DATE( '2012-07-01' )
AND
t_stamp < DATE( '2012-08-25' ) --- notice the `<` and the +1 date offset
GROUP BY
DATE( t_stamp ) ASC ;
Related
what im planning to do was that it will get all records from the past month from two table(tblshoes, tblpants) and count how many orders happened as this will be used on a google chart line chart i am trying to get all data from july 30 to 1
SELECT COUNT(*) AS shoeorder, EXTRACT(DAY FROM tlDate) as pdate
FROM tblshoes
WHERE tlDate >= CURRENT_DATE - INTERVAL 1 MONTH
GROUP BY EXTRACT(DAY FROM tlDate)
Here is what my tables looks like :
tblshoes
sname tlDate
Name Here 2017-07-15
Name Again 2017-07-14
Name again and again 2017-07-13
Name im tired 2017-07-15
Name of a patient 2017-07-10
.....
tblpants
pname tlDate
Name Here 2017-07-15
Name Again 2017-07-14
Name again and again 2017-07-13
Name im tired 2017-07-15
Name of a patient 2017-07-10
Result:
shoeorder pdate
2 15
1 14
1 13
1 10
What i want:
shoeorder pdate pantorder
0 30 0
0 29 0
0 28 0
0 27 0
0 26 0
0 25 0
0 24 0
0 23 0
0 22 0
0 21 0
0 20 0
0 19 0
0 18 0
0 17 0
0 16 0
2 15 2
1 14 1
1 13 1
0 12 0
0 11 0
1 10 1
0 9 0
0 8 0
0 7 0
0 6 0
0 5 0
0 4 0
0 3 0
0 2 0
0 1 0
You need to use full outer join...
select
coalesce(a.shoeorder, 0) as shoeorder
,coalesce(a.pdate, b.pdate) as pdate
,coalesce(b.pantorder, 0) as pantorder
from (
SELECT COUNT(*) AS shoeorder, EXTRACT(DAY FROM tlDate) as pdate
FROM tblshoes
WHERE tlDate >= CURRENT_DATE - INTERVAL 1 MONTH
GROUP BY EXTRACT(DAY FROM tlDate)
) a
left join (
SELECT COUNT(*) AS pantorder, EXTRACT(DAY FROM tlDate) as pdate
FROM tblpants
WHERE tlDate >= CURRENT_DATE - INTERVAL 1 MONTH
GROUP BY EXTRACT(DAY FROM tlDate)
) b
on a.pdate = b.pdate
union
select
coalesce(a.shoeorder, 0) as shoeorder
,coalesce(a.pdate, b.pdate) as pdate
,coalesce(b.pantorder, 0) as pantorder
from (
SELECT COUNT(*) AS shoeorder, EXTRACT(DAY FROM tlDate) as pdate
FROM tblshoes
WHERE tlDate >= CURRENT_DATE - INTERVAL 1 MONTH
GROUP BY EXTRACT(DAY FROM tlDate)
) a
right join (
SELECT COUNT(*) AS pantorder, EXTRACT(DAY FROM tlDate) as pdate
FROM tblpants
WHERE tlDate >= CURRENT_DATE - INTERVAL 1 MONTH
GROUP BY EXTRACT(DAY FROM tlDate)
) b
on a.pdate = b.pdate
SELECT COUNT(*) AS shoeorder, EXTRACT(DAY FROM tlDate) as pdate
FROM (select tlDate from tblshoes
union all
select tlDate from tblpants) sub
WHERE tlDate >= CURRENT_DATE - INTERVAL 1 MONTH
GROUP BY EXTRACT(DAY FROM tlDate)
Guess you should union both tables and then apply the group by to the result query
UPDATE: Then you need a table with all dates filled (for each day). Use the table and left join the query.
SELECT COUNT(*) AS shoeorder, EXTRACT(DAY FROM adt.tlDate) as pdate
FROM all_days_table adt
LEFT JOIN (select tlDate from tblshoes
union all
select tlDate from tblpants) sub ON adt.tlDate = sub.tlDate
WHERE tlDate >= CURRENT_DATE - INTERVAL 1 MONTH
GROUP BY EXTRACT(DAY FROM adt.tlDate)
I have a table that contains the amount of data used each day, it looks something like this:
date | bytes
------------------
2014-01-1 | 12345
2014-01-2 | 56789
2014-01-3 | 78901
...
2014-02-1 | 12345
2014-02-2 | 56789
2014-02-3 | 78901
...
What I need to do is get the last 6 monthly totals, however the month must start on the 22nd day of the month and finish on the 21st day of the following month. For the current month it should start on the 22nd and finish today.
The best I can come up with is the following, the problem is - it is very messy and doesn't seem to give the correct result.
SELECT monthname(`date`),sum(`bytes`)
FROM `trafficDaily`
WHERE `date` between STR_TO_DATE( CONCAT( "22,", MONTH( NOW( ) )-6 , ",", YEAR( NOW( ) ) ) , "%d,%m,%Y" )
and STR_TO_DATE( CONCAT( "21,", MONTH( NOW( ) ) , ",", YEAR( NOW( ) ) ) , "%d,%m,%Y" )
group by month(DATE_SUB(`date`, INTERVAL 21 DAY))
order by `date`
Thank you in advance for your help.
You can do so by using user-defined variables to track the the change of month i.e in your case month starts from 21st
SELECT
MONTHNAME(STR_TO_DATE(group_day, '%m')) month_name ,
SUM(`bytes`) `sum`
FROM (
SELECT *,
#changemonth:= CASE
WHEN DAY(`date`) > 21
THEN #month
WHEN MONTH(`date`) <> #month
THEN #month
ELSE #month - 1
END group_day,
#month:= MONTH(`date`)
FROM
t ,(SELECT #changemonth:=0,
#month:= (SELECT MONTH(`date`) FROM t
WHERE `date` > NOW() - INTERVAL 6 MONTH ORDER BY `date` LIMIT 1) aa
) tt
WHERE `date` > NOW() - INTERVAL 6 MONTH
ORDER BY `date`
) a
GROUP BY group_day
Demo for last 3 months
Edit from comments for the case when January lies in last 6 month period
SELECT
MONTHNAME(
STR_TO_DATE(
CASE WHEN group_day < 1
THEN 12 ELSE group_day
END, '%m'
)
) month_name ,
SUM(`bytes`) `sum`
FROM (
SELECT *,
#changemonth:= CASE
WHEN DAY(`date`) > 21
THEN #month
WHEN MONTH(`date`) <> #month
THEN #month
ELSE #month - 1
END group_day,
#month:= MONTH(`date`)
FROM
t ,(SELECT #changemonth:=0,
#month:= (SELECT MONTH(`date`) FROM t
WHERE `date` > NOW() - INTERVAL 6 MONTH ORDER BY `date` LIMIT 1) aa
) tt
WHERE `date` > NOW() - INTERVAL 6 MONTH
ORDER BY `date`
) a
GROUP BY group_day
Demo with January
You have at least two options:
1st option
Create a calendar table and assign the 'business month' to each days. You can prepare your table for a long time period, then you can join to that table by date and you can do the grouping. If you have to do this calculation regularry, this is a good solution. (You can upgrade and use the calendar table to do several tasks)
2nd option
You can calculate the 'business month' by the date using the following query. (Please note, that I did not tested this query, so there could be typos).
SELECT
CASE
WHEN DAY(date) >= 22 THEN CONCAT(YEAR(date), '-', MONTH(date))
ELSE CONCAT(YEAR(date - INTERVAL 1 MONTH), '-', MONTH(date - INTERVAL 1 MONTH))
END AS m,
SUM(bytes)
FROM
log -- Use your table name instead :)
GROUP BY
CASE
WHEN DAY(date) >= 22 THEN CONCAT(YEAR(date), '-', MONTH(date))
ELSE CONCAT(YEAR(date - INTERVAL 1 MONTH), '-', MONTH(date - INTERVAL 1 MONTH))
END
You can adjust the calculation to your needs.
Hello I have a table for football games, and I need to get last game and next game based on today's date.
I have tried to use this query
SELECT DATE( match_date ) AS yesterday
FROM matches
WHERE DATE( match_date ) = DATE( DATE_SUB( NOW( ) , INTERVAL 0 DAY ) )
GROUP BY yesterday
but the record can be before 2 days or 3 etc...
Also, for the Next Game If I use tomorrow date, I will not be sure if the game is exist on the next day or after.
I used this query to get all the games before today's date.
SELECT *
FROM matches
WHERE DATE( match_date ) < DATE( DATE_SUB( NOW( ) , INTERVAL 0 DAY ) )
What I need is if Today is 12-26-2012, and the table like this
----------------------------------------------
id Date Home Away
----------------------------------------------
1 2012-12-26 23 85
2 2012-12-25 11 23
3 2012-12-01 23 43
4 2012-12-29 14 23
5 2013-01-14 23 192
6 2013-01-17 23 77
INPUT: GET THE NEXT GAME FOR TEAM = 23
OUTPUT: 4
INPUT: GET THE LAST GAME FOR TEAM = 23
OUTPUT: 3
To get the last game:
SELECT DATE( match_date ) AS last_game
FROM matches
WHERE DATE( match_date ) < CURDATE()
ORDER BY match_date DESC
LIMIT 1;
To get the next game:
SELECT DATE( match_date ) AS last_game
FROM matches
WHERE DATE( match_date ) > CURDATE()
ORDER BY match_date ASC
LIMIT 1;
I'm in over my head with this query. I have a table which looks something like this (simplified):
Date Weight kg
-------------------
2012-04-16 12.4
2012-04-17 9.6
2012-04-16 5.4
2012-04-18 2.8
2012-04-16 4.5
... ...
I want the query to return this result:
Week.no. <3kg 3-7kg >7kg
----------------------------
16 2.8 9.9 22.0
... ... ... ....
This is what I have so far:
SELECT *, CONCAT(WEEK(`Date`)) AS Week, SUM(`Weight`) AS TotalWeight,
(SELECT SUM(`Weight`) FROM tbl_fangster WHERE `Weight` < 3 AND
`Date` >= '2012-04-01 00:00:00' AND `Date` <= '2012-04-30 00:00:00'
AND `Species` = 'Salmon' ) AS SumSmall
FROM tbl_fangster
WHERE `Date` >= '2012-04-01 00:00:00'
AND `Date` <= '2012-04-30 00:00:00'
AND `Species` = 'Salmon'
GROUP BY CONCAT(WEEK(`Date`))
but SumSmall returns the same number on each row, namely the total SumSmall rather than the SumSmall for each week. I've tried to copypaste my GROUP clause into the subquery, but it didn't work.
Use a CASE statement to handle the various conditions.
SELECT *, CONCAT(WEEK(`Date`)) AS Week, SUM(`Weight`) AS TotalWeight,
SUM(CASE WHEN Weight < 3 THEN Weight ELSE 0 END) AS SumSmall,
SUM(CASE WHEN Weight >= 3 AND Weight <= 7 THEN Weight ELSE 0 END) AS SumMedium,
SUM(CASE WHEN Weight > 7 THEN Weight ELSE 0 END) AS SumLarge
FROM tbl_fangster
WHERE `Date` >= '2012-04-01 00:00:00'
AND `Date` <= '2012-04-30 00:00:00'
AND `Species` = 'Salmon'
GROUP BY CONCAT(WEEK(`Date`))
I'd like to merge the results of the following three select statements horizontally. I tried using joins but no idea how to proceed since it involves COUNT and GROUP BY too.
SELECT DATE(created_at) as date,COUNT(*) as countd1 FROM b_users WHERE last_loggedin_at < DATE_ADD(created_at,INTERVAL 1 DAY) GROUP BY DATE(created_at)
SELECT DATE(created_at) as date,COUNT(*) as countd2 FROM b_users WHERE last_loggedin_at < DATE_ADD(created_at,INTERVAL 2 DAY) GROUP BY DATE(created_at)
SELECT DATE(created_at) as date,COUNT(*) as countd3 FROM b_users WHERE last_loggedin_at < DATE_ADD(created_at,INTERVAL 3 DAY) GROUP BY DATE(created_at)
The individual results would be
date countd1
2011-12-01 100
2011-12-02 120
2011-12-03 130
date countd2
2011-12-01 200
2011-12-02 220
2011-12-03 230
date countd3
2011-12-01 300
2011-12-02 320
2011-12-03 330
But I'd like to merge them so that I'll get the following result
date countd1 countd2 countd3
2011-12-01 100 200 300
2011-12-02 120 220 320
2011-12-03 130 230 330
How do I do this?
Is it possible to do something like the query below
SELECT a, COUNT(b where condition), COUNT(c where condition) FROM table GROUP BY a
.
Update
biziclop provided a great work around
SELECT DATE(created_at) AS date,
SUM(last_loggedin_at < DATE_ADD( created_at,INTERVAL 1 DAY )) AS countd1,
SUM(last_loggedin_at < DATE_ADD( created_at,INTERVAL 2 DAY )) AS countd2,
SUM(last_loggedin_at < DATE_ADD( created_at,INTERVAL 3 DAY )) AS countd3
FROM b_users GROUP BY DATE(created_at)
Solved, thank you! :)
In MySQL the results of comparisons are 1 if true, 0 if false, so you could SUM() them:
SELECT
DATE(created_at) AS date,
SUM( last_loggedin_at < DATE_ADD( created_at,INTERVAL 1 DAY )) AS countd1,
SUM( last_loggedin_at < DATE_ADD( created_at,INTERVAL 2 DAY )) AS countd2,
SUM( last_loggedin_at < DATE_ADD( created_at,INTERVAL 3 DAY )) AS countd3,
FROM b_users
GROUP BY DATE(created_at)