MYSQL: Left JOIN from two SELECT to "fill gaps" in dates - mysql

Let's say I have a table "calendar"
+------------+
| day_date |
+------------+
| 2015-01-01 |
| 2015-01-02 |
| 2015-01-03 |
| .......... |
| 2015-07-14 |
| 2015-07-15 |
+------------+
With this query I can select the WEEK (that I need)
SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS YEAR,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start
FROM calendar
GROUP BY NUM_WEEK
And this is the result:
+----------+------+------------+
| NUM_WEEK | YEAR | date_start |
+----------+------+------------+
| 29 | 2015 | 2015-07-20 |
| 30 | 2015 | 2015-07-27 |
| 31 | 2015 | 2015-08-03 |
| 32 | 2015 | 2015-08-10 |
| 33 | 2015 | 2015-08-17 |
| 34 | 2015 | 2015-08-24 |
| 35 | 2015 | 2015-08-31 |
| 36 | 2015 | 2015-09-07 |
| 37 | 2015 | 2015-09-14 |
| 38 | 2015 | 2015-09-21 |
| 39 | 2015 | 2015-09-28 |
| 40 | 2015 | 2015-10-05 |
| 41 | 2015 | 2015-10-12 |
| 42 | 2015 | 2015-10-19 |
| 43 | 2015 | 2015-10-26 |
+----------+------+------------+
Now I have another table:
+----+------------+--------+---------------------+
| id | id_account | amount | date_transaction |
+----+------------+--------+---------------------+
| 1 | 283 | 150 | 2015-06-21 15:50:47 |
| 2 | 283 | 47.74 | 2015-07-23 15:55:44 |
| 3 | 281 | 21.55 | 2015-08-24 12:27:11 |
| 4 | 283 | 11.22 | 2015-08-25 10:00:54 |
+----+------------+--------+---------------------+
They are gaps in date.
With a similar query:
SELECT WEEK(date_transaction,1) AS NUM_WEEK,
YEAR(date_transaction) AS YEAR,
STR_TO_DATE(CONCAT(YEAR(date_transaction),WEEK(date_transaction,1),' Monday'), '%X%V %W')
AS date_start,
transaction.id_account,
SUM(amount) as total FROM transaction
INNER JOIN account ON account.id_account = transaction.id_account
WHERE amount > 0 AND transaction.id_account
IN ( SELECT id_account FROM account WHERE id_customer = 12 )
GROUP BY id_account, WEEK(date_transaction,1)
I obtain this result (probably data are not accurate, referring to previous tables, just to explain).
+----------+------+------------+-----------+----------+
| NUM_WEEK | YEAR | date_start | idAccount | total |
+----------+------+------------+-----------+----------+
| 29 | 2015 | 2015-07-20 | 281 | 22377.00 |
| 30 | 2015 | 2015-07-27 | 281 | 11550.00 |
| 32 | 2015 | 2015-08-04 | 281 | 4500.00 |
| 30 | 2015 | 2015-07-27 | 283 | 1500 |
+----------+------+------------+-----------+----------+
What I would, RIGHT (or LEFT) JOINING the two tables?
The min (and max) WEEK, so I can... (see 2)
Fill the gaps with missing WEEKS with NULL VALUES.
E.g., in a more complicated resultset:
+----------+------+------------+-----------+----------+
| NUM_WEEK | YEAR | date_start | idAccount | total |
+----------+------+------------+-----------+----------+
| 29 | 2015 | 2015-07-20 | 281 | 22377.00 |
| 30 | 2015 | 2015-07-27 | 281 | 11550.00 |
| 31 | 2015 | 2015-07-02 | 281 | NULL |
| 32 | 2015 | 2015-08-09 | 281 | 4500.00 |
| 29 | 2015 | 2015-08-09 | 283 | NULL |
| 30 | 2015 | 2015-07-16 | 283 | 1500 |
| 31 | 2015 | 2015-07-16 | 283 | NULL |
| 32 | 2015 | 2015-07-16 | 283 | NULL |
+----------+------+------------+-----------+----------+
Note, for example, that id=283 now has NULL at WEEK 29, 31 and 32, for example, like id=281 has NULL in WEEK 31.
I prepared also SQLFiddle here: http://sqlfiddle.com/#!9/a8fdc/3
Thank you very much.

I take a look on your question and i came up with this solution. Here is how your query could look like:
SELECT t1.NUM_WEEK, t1.`YEAR`, t1.date_start, t1.id_account, t2.total
FROM (SELECT c.NUM_WEEK, c.`YEAR`, c.date_start, a.id_account
FROM (SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK) c
INNER JOIN account a
ON FIND_IN_SET(a.id_account, c.accounts_id)
ORDER BY a.id_account, c.NUM_WEEK) t1
LEFT JOIN
(SELECT WEEK(t.date_transaction,1) AS NUM_WEEK,
YEAR(t.date_transaction) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(t.date_transaction),WEEK(t.date_transaction,1),' Monday'), '%X%V %W') AS date_start,
t.id_account, SUM(t.amount) AS total
FROM `transaction` t
INNER JOIN account a
ON a.id_account = t.id_account
WHERE t.amount > 0 AND
t.id_account IN (SELECT id_account FROM account WHERE id_customer = 12)
GROUP BY id_account, WEEK(date_transaction,1)) t2
ON t1.NUM_WEEK = t2.NUM_WEEK AND t1.YEAR = t2.YEAR AND t1.id_account = t2.id_account;
Here is SQL Fiddle for that so you can check up result. Hope that is what are you looking for.
Little explanation:
First think i done is that I little modified your first query where you extract data from table calendar and add there one new column called accounts_id. That query now look's like this:
SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK
Please pay attention on this line in SELECT statement
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
Note that when you select for specific customer you need to change customer ID in this line too!!!
Here is Fiddle so you can check result that this query produce.
This is necessary because we need to connect each week with each account to get desired result.
Next step is to extend previous query so we could separate accounts_id column (look result of previous query) so we could get row for each value in that column. Extended query look like this:
SELECT c.NUM_WEEK, c.`YEAR`, c.date_start, a.id_account
FROM (SELECT WEEK(day_date,1) AS NUM_WEEK,
YEAR(day_date) AS `YEAR`,
STR_TO_DATE(CONCAT(YEAR(day_date),WEEK(day_date,1),' Monday'), '%X%V %W') AS date_start,
(SELECT GROUP_CONCAT(id_account) FROM account WHERE id_customer=12) AS accounts_id
FROM calendar
GROUP BY NUM_WEEK) c
INNER JOIN account a
ON FIND_IN_SET(a.id_account, c.accounts_id)
ORDER BY a.id_account, c.NUM_WEEK
and output you can see in this Fiddle
After that all we need to do is to make left join between this query and query you already wrote in your question (last query).
There might be a better solution or even this one maybe can be improved a little, but I don't have much time now to deal with that and this is the first think that cross my mind...
GL!
P. S. pay attention when you use reserved word in MySQL like YEAR, TRANSACTION etc for column name (as column_name).. that can cause you a treble if have to use them in name of column or table use backquote () to mark them (asyear`)...

Related

MySQL Query to get the monthly data difference

select * from new_joiner;
+------+--------------+
| id | date_of_join |
+------+--------------+
| 1 | 2020-01-10 |
| 2 | 2020-01-02 |
| 3 | 2020-01-05 |
| 4 | 2020-02-10 |
| 5 | 2020-02-11 |
| 6 | 2020-07-11 |
| 7 | 2020-07-11 |
| 8 | 2020-07-11 |
| 9 | 2020-07-11 |
| 10 | 2020-07-11 |
| 11 | 2020-05-01 |
| 12 | 2020-05-02 |
| 13 | 2020-05-03 |
| 14 | 2020-05-04 |
| 15 | 2020-05-05 |
| 16 | 2020-05-05 |
| 17 | 2020-05-06 |
+------+--------------+
select MONTHNAME(date_of_join) as MONTHNAME,
count(id) as JOINEE
from new_joiner
where MONTH(date_of_join)>=1
group by MONTH(date_of_join);
+-----------+--------+
| MONTHNAME | JOINEE |
+-----------+--------+
| January | 3 |
| February | 2 |
| May | 7 |
| July | 5 |
+-----------+--------+
I want a query that gives me the monthly data change compare to previous month.
For example: new joinee in Jan was 3, and in Feb it was 2, so compare to Jan in Feb month -1 joined, so the query should output me:
+-----------+-------------+
| MONTHNAME | JOINEE_DIFF |
+-----------+-------------+
| February | -1 |
| Mar | -2 |
| April | 0 |
| May | 7 |
| June | -7 |
| July | 5 |
| Aug | -5 |
| Sep | 0 |
| Oct | 0 |
| Nov | 0 |
| Dec | 0 |
+-----------+-------------+
Ignore Jan as it doesn't have a previous month and assume we have data only for a given year say 2020. Require data for all months from Feb to Dec.
Assuming you have data for every month, you can use lag():
select MONTHNAME(date_of_join) as MONTHNAME,
count(id) as JOINEE,
(count(*) - lag(count(*)) over (order by min(date_of_join)) as diff
from new_joiner
where MONTH(date_of_join) >= 1
group by MONTH(date_of_join);
Note that using months without years if fraught with peril. Also, the month() of any well-formed date should be larger than 1.
All this suggests a query more like:
select *
from (select MONTHNAME(date_of_join) as MONTHNAME,
count(id) as JOINEE,
(count(*) - lag(count(*)) over (order by min(date_of_join)) as diff,
min(date_of_join) as min_date_of_join
from new_joiner
where date_of_join >= '2020-01-01' and date_of_join < '2021-01-01'
group by MONTH(date_of_join)
) t
where diff is not null
order by min_date_of_join;
Use a correlated subquery to get the number of joinees of previous month and subtract it:
SELECT
t.monthname,
joinee - (SELECT COUNT(*) FROM new_joiner WHERE MONTH(date_of_join) = t.month - 1) JOINEE_DIFF
FROM (
SELECT MONTH(date_of_join) month, MONTHNAME(date_of_join) monthname,
COUNT(id) joinee
FROM new_joiner
GROUP BY month, monthname
) t
WHERE t.month > 1;

Sum and subtract from another relation table in one query

I have two tables, one is called Attendance and the other is called Timeslices, I am trying to get the total seconds of Attendances subtracted from Timeslices for the current week and also with Doctrine.
I've got to get the rows but I have to sum and subtract each of them out of the query, but I need to learn to do it in one query.
This is the structure of the Attendance Table:
SELECT * FROM attendance;
+----+---------+---------------------+--------+---------------------+---------------------+
| id | user_id | day | status | check_in | check_out |
+----+---------+---------------------+--------+---------------------+---------------------+
| 1 | 1 | 2019-12-18 00:00:00 | end | 2019-12-18 09:52:00 | 2019-12-18 23:37:02 |
| 2 | 1 | 2019-12-19 00:00:00 | end | 2019-12-19 12:12:00 | 2019-12-19 21:05:00 |
+----+---------+---------------------+--------+---------------------+---------------------+
Timeslice table:
SELECT * FROM timeslice;
+----+---------------+-------------------------------------+---------------------+---------------------+---------------------+
| id | attendance_id | title | day | start_at | stopped_at |
+----+---------------+-------------------------------------+---------------------+---------------------+---------------------+
| 20 | 1 | Sacar al perro, ducharme y vestirme | 2019-12-18 00:00:00 | 2019-12-18 15:57:50 | 2019-12-18 12:15:36 |
| 21 | 1 | Dormir | 2019-12-18 00:00:00 | 2019-12-18 18:44:30 | 2019-12-18 16:16:44 |
| 22 | 1 | Descansar | 2019-12-18 00:00:00 | 2019-12-18 23:04:53 | 2019-12-18 20:56:29 |
| 23 | 2 | Comer | 2019-12-19 00:00:00 | 2019-12-19 16:03:00 | 2019-12-19 15:37:00 |
| 24 | 2 | Comer | 2019-12-19 00:00:00 | 2019-12-19 16:55:00 | 2019-12-19 16:17:00 |
| 25 | 2 | ducharme | 2019-12-19 00:00:00 | 2019-12-19 19:58:00 | 2019-12-19 17:20:00 |
+----+---------------+-------------------------------------+---------------------+---------------------+---------------------+
This is my current query in which I get the results, but then I have to calculate out of the query to get the desired result and SQLFiddle:
http://sqlfiddle.com/#!9/646be/3
SELECT SUM(TIME_TO_SEC(TIMEDIFF(a.check_out, a.check_in))) AS secondsAttendance
, ( SELECT SUM(TIME_TO_SEC(TIMEDIFF(t.start_at, t.stopped_at)))
FROM timeslice t
WHERE t.attendance_id = a.id
) secondsPauses
FROM attendance a
GROUP
BY a.id
What I need as I said before is to be able to do it in the same query without having to use PHP and with Doctrine
I've changed my answer after your comments. If you only need the value it seams that all you need to do is to use you initial query (with a few twicks) as a
subquery in the FROM clause (Derived Table) and then, do your calculations over it. In this case simply need to SUM the result of subtracting the secondsPauses to the secondsAttendance, like this:
-- make the calculation you need over the results
SELECT SUM(Results.secondsAttendance - Results.secondsPauses) as ActualValue
FROM (
-- use you initial results as a subquery and name it as Results
SELECT
SUM(TIME_TO_SEC(TIMEDIFF(a.check_out, a.check_in))) AS secondsAttendance,
(SELECT SUM(TIME_TO_SEC(TIMEDIFF(t.start_at, t.stopped_at)))
FROM timeslice t WHERE t.attendance_id = a.id) AS secondsPauses
FROM attendance a
-- filter date for the current week
where yearweek(DATE(a.check_in), 1) = yearweek(curdate(), 1)
GROUP BY a.id
) Results;
The result is:
+-------------+
| ActualValue |
+-------------+
| 38258 |
+-------------+
SqlFiddle in here

mysql query for getting distinct and lastest record

I have made a view(joining four tables) like below:
ID | BookID | date | points |
1 | 11 | 2014-11-01 | 15 |
1 | 11 | 2015-01-01 | 16 |
1 | 11 | 2014-12-01 | 17 |
1 | 12 | 2014-02-11 | 18 |
1 | 12 | 2014-03-11 | 19 |
1 | 12 | 2014-04-11 | 15 |
1 | 13 | 2014-12-23 | 121 |
1 | 14 | 2014-01-15 | 113 |
1 | 14 | 2014-02-08 | 112 |
I want the result of this view as below
ID | BookID | Date | points |
1 | 11 | 2015-01-01 | 16 |
1 | 12 | 2014-04-11 | 15 |
1 | 13 | 2014-12-23 | 121 |
1 | 14 | 2014-02-08 | 112 |
It should be like Distincit Book ID with max date and showing as seprate points.
So far i have tried the group by with join and group by with date. But it is getting a bit over as i am unable to find a solution to this.
My Query is:
SELECT m1.* FROM viewPoints m1 LEFT JOIN viewPoints m2
ON (m1.BookID = m2.BookID AND m1.Date < m2.Date)
WHERE m1.ID= 1 and m2.Date IS NULL
ORDER BY m1.BookID
Any help! Thanks in Advance.
Maybe this is what you want?
select v.*
from viewPoints v
join (
select
BookID,
max(date) max_date
from viewPoints
where points is not null
group by BookID
) v2 on v.BookID = v2.BookID and v.date = v2.max_date
where v.points is not null
order by v.BookID
Sample SQL Fiddle
Sample output:
| ID | BOOKID | DATE | POINTS |
|----|--------|---------------------------------|--------|
| 1 | 11 | January, 01 2015 00:00:00+0000 | 16 |
| 1 | 12 | April, 11 2014 00:00:00+0000 | 15 |
| 1 | 13 | December, 23 2014 00:00:00+0000 | 121 |
| 1 | 14 | February, 08 2014 00:00:00+0000 | 112 |
SELECT *
FROM tablename
WHERE DATE
IN (
SELECT MAX( DATE )
FROM tablename
GROUP BY bookid
ORDER BY DATE DESC
)
ORDER BY DATE DESC
CREATE VIEW [BOOKLIST] AS
SELECT m1.* FROM viewPoints m1 LEFT JOIN viewPoints m2
ON (m1.BookID = m2.BookID AND m1.Date < m2.Date)
WHERE m1.ID= 1 and m2.Date IS NULL
ORDER BY m1.BookID
SELECT ID, DISTINCT BookID, Date, points FROM BOOKLIST
WHERE Date BETWEEN "start date" AND "end date"

Fetching Total Sale of each day and month from database

I have table with column c_date as datetime, total as int type in mysql, and i want to print out sale of each day, and total sale of each month, and total sale annually including day, month, year where there was no sale.
Currently for daily sale, I am running below query :
mysql> select date(c_date) as date, sum(total) as total_sale from sale group by date;
+------------+------------+
| date | total_sale |
+------------+------------+
| 2013-10-3 | 798 |
| 2013-10-6 | 114 |
+------------+------------+
but, i want something like this :
mysql> select date(c_date) as date, sum(total) as total_sale from sale group by date;
+------------+------------+
| date | total_sale |
+------------+------------+
| 2013-10-1 | 0 |
| 2013-10-2 | 0 |
| 2013-10-3 | 798 |
| 2013-10-4 | 0 |
| 2013-10-5 | 0 |
| 2013-10-6 | 114 |
+------------+------------+
and for Monthly, I am getting this :
mysql> select c_date, month(c_date) as month, year(c_date) as year, sum(total) as total from sale group by c_date order by c_date;
+---------------------+-------+------+-------+
| c_date | month | year | total |
+---------------------+-------+------+-------+
| 2013-10-3 02:40:06 | 10 | 2013 | 228 |
| 2013-10-3 02:41:58 | 10 | 2013 | 114 |
| 2013-10-3 02:44:36 | 10 | 2013 | 114 |
| 2013-10-3 02:46:40 | 10 | 2013 | 114 |
| 2013-10-3 02:49:15 | 10 | 2013 | 114 |
| 2013-10-3 02:53:36 | 10 | 2013 | 114 |
| 2013-10-6 07:43:27 | 10 | 2013 | 114 |
+---------------------+-------+------+-------+
But i want something like this :
mysql> select c_date, month(c_date) as month, year(c_date) as year, sum(total) as total from sale group by c_date order by c_date;
+---------------------+-------+------+-------+
| c_date | month | year | total |
+---------------------+-------+------+-------+
| 2013-1-3 02:40:06 | 1 | 2013 | 0 |
| 2013-2-3 02:41:58 | 2 | 2013 | 0 |
| 2013-3-3 02:44:36 | 3 | 2013 | 0 |
| 2013-4-3 02:46:40 | 4 | 2013 | 0 |
| 2013-5-3 02:49:15 | 5 | 2013 | 0 |
| 2013-6-3 02:53:36 | 6 | 2013 | 0 |
| 2013-7-6 07:43:27 | 7 | 2013 | 0 |
| 2013-8-3 02:44:36 | 8 | 2013 | 0 |
| 2013-9-3 02:46:40 | 9 | 2013 | 0 |
| 2013-10-3 02:49:15 | 10 | 2013 | 912 |
| 2013-11-3 02:53:36 | 11 | 2013 | 0 |
| 2013-12-6 07:43:27 | 12 | 2013 | 0 |
+---------------------+-------+------+-------+
Is this possible with MysqL ?
Since it's impossible to use sequences in MySQL (actually, they simply do not exist there), you'll have to create your dates range table first. That will be like:
CREATE TABLE dates_range (record_date DATE)
and then fill this table with dates, starting from minimum among dates, that exist in your sale table and till maximum.
After this, using SQL LEFT JOIN operator, you'll be able to aggregate your data like this:
SELECT
YEAR(dates_range.record_date),
MONTH(dates_range.record_date),
DAY(dates_range.record_date),
COALESCE(SUM(sale.total), 0) AS total_sum
FROM
dates_range
LEFT JOIN sale
ON dates_range.record_date=DATE(sale.c_date)
GROUP BY
YEAR(dates_range.record_date),
MONTH(dates_range.record_date),
DAY(dates_range.record_date)
it looks to me that you need an outer join with a calendar table.
Imagine a calendar table populated like:
Calendar
Year Month Day
2013 201310 2013-10-1
2013 201310 2013-10-2
...
Then you can write a query like
select date(c_day) as date,
sum(total) as total_sale
from calendar c
left outer join sale s
on c.day = s.c_date
where c.month = 201310
group by c_day
having c_day <= max(s.c_date); -- this is to avoid to show all
-- days for October

MySQL: Finding Maximum Value for a Column for each location and server

I have the following table:
++++++++++++++++++++++++++++++++++++++++++++++++++
| location | server | datetime | max_cpu |
++++++++++++++++++++++++++++++++++++++++++++++++++
| Chicago | 1 | 2013-05-01 00:00 | 10 |
| Chicago | 1 | 2013-05-01 01:00 | 15 |
| Chicago | 1 | 2013-05-01 02:00 | 11 |
| Chicago | 2 | 2013-05-01 00:00 | 8 |
| Chicago | 2 | 2013-05-01 01:00 | 12 |
| Chicago | 2 | 2013-05-01 02:00 | 13 |
| Atlanta | 1 | 2013-05-01 00:00 | 11 |
| Atlanta | 1 | 2013-05-01 01:00 | 12 |
| Atlanta | 1 | 2013-05-01 02:00 | 19 |
| Atlanta | 2 | 2013-05-01 00:00 | 21 |
| Atlanta | 2 | 2013-05-01 01:00 | 15 |
| Atlanta | 2 | 2013-05-01 02:00 | 17 |
I need the maximum CPU for each box in each location for a given day, e.g.
++++++++++++++++++++++++++++++++++++++++++++++++++
| location | server | datetime | max_cpu |
++++++++++++++++++++++++++++++++++++++++++++++++++
| Chicago | 1 | 2013-05-01 01:00 | 15 |
| Chicago | 2 | 2013-05-01 02:00 | 13 |
| Atlanta | 1 | 2013-05-01 02:00 | 19 |
| Atlanta | 2 | 2013-05-01 00:00 | 21 |
I know how to do this for a single criteria (e.g. just location) and tried to expand upon that (see below) but it is not giving me the output I need.
SELECT a.location, a.server, a.datetime, a.max_cpu
FROM mytable as a INNER JOIN
(
SELECT location, server, max(max_cpu) as max_cpu
FROM mytable
GROUP BY location, server
)
AS b ON
(
a.location = b.location
AND a.server = b.server
AND a.max_cpu = b.max_cpu
)
You can do this by finding the max cpu and joining back to the original table.
It seems that you want the time of the max as well as the amount (this is not clearly stated in the text, but clear in the results):
select t.*
from mytable t join
(select location, server, DATE(datetime) as thedate, MAX(max_cpu) as maxmaxcpu
from mytable t
group by location, server, DATE(datetime)
) lsd
on lsd.location = t.location and lsd.server = t.server and
lsd.thedate = DATE(t.datetime) and lsd.maxmaxcpu = t.max_cpu
This calculates the maxcpu on each day and then joins back to get the appropriate row or rows in the original data. If there is more than one record with the max, you'll get all the records. If you only want one, you can add group by location, server, day(datetime) to the query.
This better answers the "for a given day" part of the question. Since you can ignore the time, this avoids that date hacky thing, is a tad simpler, and if multiple times have the same CPU for that server, it doesn't show duplicates:
select distinct a.location, a.server, a.datetime, a.max_cpu
from
mytable a
inner join (
select location, server, max(max_cpu) as max
from mytable
where
datetime >= ? -- start of day
and datetime < ? -- start of next day
group by location, server
) b on a.location=b.location and a.server=b.server and a.max_cpu as max
where
a.datetime >= ? -- start of day
a.and datetime < ? -- start of next day
Query (works only if max_cpu is unique per location, server and Date ):
SQLFIDDLEExample
SELECT t1.*
FROM Table1 t1
WHERE t1.max_cpu = (SELECT MAX(t2.max_cpu)
FROM Table1 t2
WHERE t2.location = t1.location
AND t2.server = t1.server
AND DATE(t2.datetime) = DATE(t1.datetime))
Result:
| LOCATION | SERVER | DATETIME | MAX_CPU |
------------------------------------------------------------
| Chicago | 1 | May, 01 2013 01:00:00+0000 | 15 |
| Chicago | 2 | May, 01 2013 02:00:00+0000 | 13 |
| Atlanta | 1 | May, 01 2013 02:00:00+0000 | 19 |
| Atlanta | 2 | May, 01 2013 00:00:00+0000 | 21 |