Retrieve row for each group having the maximum date - mysql

I have this MySQL table:
ID Number Date
1 4 2015-05-30
2 4 2016-03-15
3 5 2016-04-01
4 5 2016-05-01
I want to get unique Number but only get those with the highest date. The result must get ONLY:
ID Number Date
2 4 2016-03-15
4 5 2016-05-01
I tried:
SELECT
*
FROM emp_events ee
Date = (SELECT MAX(Date) FROM emp_events ee1 WHERE ee1.Number = ee.Number));
but not getting all the desired results.

One way you can accomplish through INNER JOIN
SELECT
E.*
FROM emp_events E
INNER JOIN(
SELECT
Number,
MAX(Date) max_date
FROM emp_events ee
GROUP BY Number
) AS t
ON E.Number = t.Number AND E.Date = t.max_date
Another way could be using IN:
SELECT
E.*
FROM emp_events E
WHERE (E.Number,E.Date) IN
(
SELECT
Number,
MAX(Date) max_date
FROM emp_events ee
GROUP BY Number
)

Try This
You have to GROUP BY number and also to find max date set ORDER BY date ASC in Query
SELECT e.*
FROM(
SELECT ee.*
FROM `emp_events` AS ee
ORDER BY ee.date ASC
) AS e
GROUP BY e.number

Related

MySQL Query to get each sales per month

I have 2 tables in Mysql. I want to regroup and count the Number of Orderid per month for each customer. If there is no order, I would like to add 0.
Customer Table
CustomerID
1
2
3
Order Table
OrderId CustomerID Date
1 1 2022-01-02
2 1 2022-01-04
3 2 2022-02-03
4 2 2022-03-03
Expect results
CustomerID Date CountOrderID
1 2022-01 2
2 2022-01 1
3 2022-01 0
1 2022-02 0
2 2022-02 1
3 2022-02 0
1 2022-03 0
2 2022-03 1
3 2022-03 0
How I can do this in Mysql?
SELECT customer.CustomerID,
year_month.y_m AS `Date`,
COUNT(order.OrderId) AS CountOrderID
FROM customer
CROSS JOIN (
SELECT DISTINCT DATE_FORMAT(`date`, '%Y-%m') AS y_m
FROM order
) AS year_month
LEFT JOIN order ON order.CustomerID = customer.CustomerID
AND DATE_FORMAT(order.`date`, '%Y-%m') = year_month.y_m
GROUP BY 1, 2;
If order table does not contains for some year and month then according row won't present in the output. If you need in it then you'd generate calendar table instead of year_month subquery.
you can reduce the number of cte's I added more here to explain the steps:
first you need the format year and month, for that I used DATE_FORMAT() function
since you need to have all the combination of dates and the year month you need a cross join. This will produce all the distinct dates with all the distinct customer id's. In other words all the pairs between dates and customer id
once you have a table with all the combinations you need to pass the actual data with the left join this will produce null where you actually don't have rows and hence will produce 0 when the count is performed
the last step is simply count function
with main as (
select distinct DATE_FORMAT(date,'%Y-%m') as year_month from order
),
calendar as (
select * from customer
cross join main
),
joining_all as (
select
calendar.*,
order. OrderId
left join order
on calendar.CustomerID = order.CustomerID
and calendar.year_month = DATE_FORMAT(order.date,'%Y-%m')
)
select
CustomerID,
year_month as Date,
count(OrderId) as CountOrderID
from joining_all
group by 1,2
maybe the shorter version can work with the code below. if runs into syntax you can use the one above
with main as (
select distinct DATE_FORMAT(date,'%Y-%m') as year_month from order
cross join customer
)
select
main.CustomerID,
main.year_month as Date,
count(order.OrderId) as CountOrderID
from main
left join order
on main.CustomerID = order.CustomerID
and main.year_month = DATE_FORMAT(order.date,'%Y-%m')
group by 1,2

Find the value of one column based on maximum value in another column per group

I have a query which gives me three columns: an ID, the day of week of event and count of how many events each day of week has, i.e.
ID Day_Name Cnt
1 Thursday 1
2 Monday 3
2 Thursday 2
2 Sunday 2
3 Tuesday 7
3 Wednesday 3
I get this by using query
SELECT P.ID, DAYNAME(E.EVENT_DATE) AS Day_Name, COUNT(*) AS Cnt
FROM EVENT AS E
INNER JOIN PERSON AS P
ON P.ID_2 = E.ID_2
WHERE E.EVENT_DATE > '2016-01-01'
AND E.EVENT_STATUS LIKE '%OCCURED%'
GROUP BY P.ID, DAYNAME(E.EVENT_DATE)
I would like to reduce this query to only return the day of week for each user with the maximum count. At the same time, I would like to change the column with counts to instead show the frequency of events for that weekday. For the example above I would like to change the output to be
ID Day_Name Frequency
1 Thursday 1
2 Monday 0.429
3 Tuesday 0.7
Thankful if anyone got an idea
To get the expected result set you could do your calculation in outer query like
SELECT ID,
SUBSTRING_INDEX(GROUP_CONCAT(Day_Name ORDER BY Cnt DESC),',',1) Day_Name,
MAX(Cnt)/SUM(Cnt) Frequency
FROM(
SELECT P.ID, DAYNAME(E.EVENT_DATE) AS Day_Name, COUNT(*) AS Cnt
FROM EVENT AS E
INNER JOIN PERSON AS P
ON P.ID_2 = E.ID_2
WHERE E.EVENT_DATE > '2016-01-01'
AND E.EVENT_STATUS LIKE '%OCCURED%'
GROUP BY P.ID, DAYNAME(E.EVENT_DATE)
) t
GROUP BY ID
So here's a partial answer...
SELECT a.*
FROM ([your query here]) a
JOIN
( SELECT id,MAX(cnt) cnt FROM ([your query here]) GROUP BY id ) b
ON b.id = a.id
AND b.cnt = a.cnt;
For a more complete answer I suggest you provide the original 18 row data set. See: Why should I provide an MCVE for what seems to me to be a very simple SQL query?

MYSQL: How to get Maximum and Second Maximum Date in single query

I am trying to select Maximum Date and Second Max Date but can't get success.
This is table data.
ID Country DATE
1 Canada 2016-05-26
2 Canada 2016-05-25
3 Canada 2016-05-24
4 USA 2016-04-02
5 USA 2016-04-01
6 USA 2016-03-20
Expecting Output
Country Max_Date 2nd_Date
Canada 2016-05-26 2016-05-25
USA 2016-04-02 2016-04-01
What I have done so for:
Get Max Date using this query.
select Country, MAX(Date) from tbl GROUP BY (Country);
For Second Max date but failed to get result:
SELECT Country, MAX(date) FROM tbl WHERE Date NOT IN
( select MAX(FROM) from tbl GROUP BY (Country)) GROUP BY (Country)
What should I try to get expected output. Thanks
Or you could try this
SELECT s.Country, Max(s.Date) Max_Date,
(SELECT t.Date
FROM tbl t
Where s.Country=t.Country
ORDER BY Date DESC
LIMIT 1,1) 2nd_Date
FROM tbl s
GROUP BY COUNTRY;
The LIMIT clause is zero based, so using parameters 1,1 skips the first (ie max) value & returns just one value (2nd max).
NOTE - if the max date is duplicated the query will return Max_Date & 2nd_Date as the same value - if that is not what you want, then you can add DISTINCT to the inner query.
No need for nested queries to solve this:
SELECT t1.country, max(t1.date), max(t2.date)
FROM tbl t1
JOIN tbl t2 ON t1.country = t2.country AND t2.date < t1.date
GROUP BY t1.country;
This can be a pain. Here is one method:
select t.country, maxdate, max(t.date) as secondate
from tbl t left join
(select country, max(date) as maxdate
from tbl
group by country
) c
on t.country = c.country and t.date < c.maxdate
group by t.country;
Try this one
Select Country, MAX(Date) As Date From tbl GROUP BY Country Order By Date Desc Limit 2;

Get greatest common value in a column across tables

I have 4 tables (say A, B, C and D) all with the column 'date'. I need to find the greatest common date value across all four tables. That is, the greatest value of date that exists in all four tables. How can I do this?
For now, I'm making do with finding the MIN of the MAX date values of all four tables, but this fails in the cases where the MIN exists in one table but not in the second.
Here is an example to make things clearer :
A.date
------
2015-03-31
2015-03-30
2015-03-29
2015-03-27
B.date
------
2015-03-30
2015-03-29
2015-03-28
2015-03-27
C.date
------
2015-03-29
2015-03-27
2015-03-26
2015-03-25
D.date
------
2015-03-28
2015-03-27
2015-03-26
2015-03-25
What I was doing to find the highest common date was :
SELECT MIN(max_date) FROM (
SELECT MAX(date) AS max_date FROM A
UNION
SELECT MAX(date) AS max_date FROM B
UNION
SELECT MAX(date) AS max_date FROM C
UNION
SELECT MAX(date) AS max_date FROM D
) T;
This gives me 2015-03-28, but then I realized that some tables might not have this date at all. The date I actually want to get is 2015-03-27.
Here is one method:
select date
from (select date, 'a' as which from a union all
select date, 'b' as which from b union all
select date, 'c' as which from c union all
select date, 'd' as which from d
) x
group by date
having count(distinct which) = 4
order by date desc
limit 1;
The following version might perform a bit better, especially if you have an index on date in each table:
select date
from (select distinct date, 'a' as which from a union all
select distinct date, 'b' as which from b union all
select distinct date, 'c' as which from c union all
select distinct date, 'd' as which from d
) x
group by date
having count(*) = 4
order by date desc
limit 1;
You need to get an intersection of all date values across the 4 separate tables. Then, select the MAX of these values:
SELECT MAX(date)
FROM A
WHERE date IN (
SELECT date
FROM B
WHERE date IN (
SELECT date
FROM C
WHERE date IN (
SELECT date
FROM D)))
SQL Fiddle Demo here

What's the most efficient way to generate this report?

Given a table (daily_sales) with say 100k rows of the following data/columns:
id rep sales date
1 a 123 12/15/2011
2 b 153 12/15/2011
3 a 11 12/14/2011
4 a 300 12/13/2011
5 a 120 12/12/2011
6 b 161 11/15/2011
7 a 3 11/14/2011
8 c 13 11/14/2011
9 c 44 11/13/2011
What would be the most efficient way to write a report (completely in SQL) showing the two most recent entries (rep, sales, date) for each name, so the output would be:
a 123 12/15/2011
a 11 12/14/2011
b 153 12/15/2011
b 161 11/15/2011
c 13 11/14/2011
c 44 11/13/2011
Thanks!
FYI, your example is using mostly reserved words and makes it horrid for us to attempt to program against. If you've got the real table columns, gives those to us. This is postgres:
select name,value, max(date)
from the_table_name_you_neglect_to_give_us
group by 1,2
That'll give you a list of first name,value,max(date)...though I gotta ask why give us a column called value if it doesn't change in the example?
Lets say you do have an id column...we'll be consistent with your scheme and call it 'ID'...
select b.id from
(select name,value, max(date) date
from the_table_name_you_neglect_to_give_us
group by 1,2) a
inner join the_table_name_you_neglect_to_give_us b on a.name=b.name and a.value=b.value and a.date = b.date
This gives a list of all ID's that are the max...put it together:
select name,value, max(date)
from the_table_name_you_neglect_to_give_us
group by 1,2
union all
select name,value, max(date)
from the_table_name_you_neglect_to_give_us
where id not in
(select b.id from
(select name,value, max(date) date
from the_table_name_you_neglect_to_give_us
group by 1,2) a
inner join the_table_name_you_neglect_to_give_us b on a.name=b.name and a.value=b.value and a.date = b.date)
Hoping my syntax is right...should be close at any rate. I'd put a bracket around that entire thing then select * from (above query) order by name...gives you the order you want.
For MySQL, explained in #Quassnoi's blog, an index on (name, date) and using this:
SELECT t.*
FROM (
SELECT name,
COALESCE(
(
SELECT date
FROM tableX ti
WHERE ti.name = dto.name
ORDER BY
ti.name, ti.date DESC
LIMIT 1
OFFSET 1 --- this is set to 2-1
), CAST('1000-01-01' AS DATE)) AS mdate
FROM (
SELECT DISTINCT name
FROM tableX dt
) dto
) tg
, tableX t
WHERE t.name >= tg.name
AND t.name <= tg.name
AND t.date >= tg.mdate
If I understand what you mean.. Then this MIGHT be helpful:
SELECT main.name, main.value, main.date
FROM tablename AS main
LEFT OUTER JOIN tablename AS ctr
ON main.name = ctr.rname
AND main.date <= ctr.rdate
GROUP BY main.name, main.date
HAVING COUNT(*) <= 2
ORDER BY main.name ASC, main.date DESC
I know the SQL is shorter than the other posts, but just give it a try first..