mysql - group by to get oldest and newest dates into one row - mysql

I have tbl_events
key userID date
1 1 1.1.2000
2 1 1.1.2017
3 2 2.2.1990
I'm trying to get this:
select distinct userID, date [that is earliest eg row 1] as earliest_date,
date [that is latest eg row 2] as latest_date
from tbl_events
if a userid has only one row in tbl_events then tbl_events.date would serve as both the earliest and latest_date
ie my result would be:
userID earliest_date latest_date
1 1.1.2000 1.1.2017
2 2.2.1990 2.2.1990
I can do this rather inefficiently with lots of looping but I'm wondering if there is a way to do this with "group by" or i have seen queries that seem to contain additional select statements in brackets
If anyone can please point me in the right direction I'd be very grateful.
Thank you.
Nick

You can use MAX() and MIN() aggregate function probably saying
select userid, max(`date`) as earliest_date,
min(`date`) as furthest_date
from tbl
group by userid;

Related

get highest date between two date column in mysql query

Hello I have two column of date time of multiple rows i want to fetch row with latest date(highest) between two column of all record. Please check below:
ID|Date1 |Date2
1 |2021-06-10 19:03:36 |Null
2 |2021-06-11 19:33:41 |2021-06-16 09:49:41
3 |2021-06-16 20:04:24 |Null
I want to get highest date from all record of two column(Date1 and Date2). From above table, I want third row date because this is highest date(2021-06-16 20:04:24) from all record of two column. If we change the date1 column row 3 by 2021-06-16 09:20:41 then result will be row 2 because highest date record found in date2. Please help me for creating mysql query for getting full data row
If you want only 1 row in the results and you don't care about ties, then use GREATEST() to get the max date in each row, sort by that max date descending and use LIMIT 1 to pick the top row:
SELECT *
FROM tablename
ORDER BY GREATEST(COALESCE(Date1, '1000-01-01'), COALESCE(Date2, '1000-01-01')) DESC
LIMIT 1
If Date1 is not nullable use COALESCE() only for Date2:
SELECT *
FROM tablename
ORDER BY GREATEST(Date1, COALESCE(Date2, '1000-01-01')) DESC
LIMIT 1
See the demo.
You can union the two columns and get the MAX():
SELECT MAX(dateColumns)
FROM
(
SELECT DATE1 as dateColumns FROM yourtable
UNION ALL
SELECT DATE2 FROM yourtable
) sub
One way to do this with somewhat minimal SQL where "yourtable" is whatever the name of your table is:
select ID, Date1, Date2
from yourtable
where greatest(
coalesce(Date1,'1900-01-01'),
coalesce(Date2,'1900-01-01')
) in (
select max(greatest(
coalesce(Date1,'1900-01-01'),
coalesce(Date2,'1900-01-01')
)) from yourtable
)
However, performance of this kind of query may not scale for huge tables. EDIT: Updated to include coalesce() of null dates to an arbitrarily "early" date.

Query SELECT DISTINCT count()

Hello there I have the following doubt I want to count how many times in a month I enter data.
My database is:
Date:
10/2010
10/2010
09/2010
08/2010
I have the following query.
SELECT DISTINCT (date)
FROM employee
WHERE date
IN (SELECT date
FROM employee
GROUP BY date
HAVING count( date ) >0)
ORDER BY date DESC;
This query gives me:
Date:
10/2017
8/2017
9/2017
But I want you to give me something like that.
Count | Date
2 | 10/2017
1 | 9/2017
1 | 10/2017
I hope I have explained my regards.
You're overcomplicating it; no subquery, or DISTINCT, needed.
SELECT `date`, count(*)
FROM `employee`
GROUP BY `date`
HAVING count(*) > 0
ORDER BY `date` DESC;
I am a little confused as to what reason you would have for the HAVING count() > 0 though; the only way something could have a zero count would mean it wasn't in the table (and therefore wouldn't show up anyway).
Other observations:
DISTINCT is not a function; enclosing the date in parenthesis in the SELECT clause has absolutely no effect. (Also, DISTINCT is almost never appropriate for a GROUPing query.)
COUNT(somefield) is the same as COUNT(1), COUNT(*). If you want the count of unique values you can do COUNT(DISTINCT somefield); but it wouldn't make sense to COUNT(DISTINCT groupingfield) as that would always result in 1.
The query you wrote is a bit complicated. Distinct and group by are doing the same thing for you here. When you do a group by count will automatically give you the count of grouped rows. Also you will have unique dates as well. Try this.
SELECT count(date), date
FROM employee
GROUP BY date
HAVING count( date ) >0
ORDER BY date DESC;

How to get the number of days between two dates

I have a situation where I need to find the number of days that have passed between two rows with date fields. The rows that the calculation needs to be made are not sorted.
Here is the structure of the table
Folio DATE
1 6/1/2015
2 4/1/2015
1 3/1/2015
4 2/1/2015
1 1/1/2015
Basically, I would need to sort by date and keep only the last two transactions grouped by folio. so in this example, the transaction by folio 1 on 1/1/2015 would be ignored.
Suppose that I need to do the following:
1. Group by folio number
2. only count the days between the last two transactions by folio. For example, folio #1 would only include the transactions from 6/1/2015 and 3/1/2015.
The result I'm looking for:
Folio FirstDATE LastDate #ofDays
1 3/1/2015 6/1/2015 90
Any MySQL pros out there? My skills are still in newbie territory. Thank you!
UPDATE:
I've managed to come up with the following:
SELECT
SubQuery.`Folio Number`,
SubQuery.LatestClosing,
SubQuery.FirstClosing,
DATEDIFF(SubQuery.LatestClosing, SubQuery.FirstClosing) AS numofdays
FROM (SELECT
Subquery.`Folio Number`,
SubQuery.LatestClosing,
SubQuery.FirstClosing
FROM (SELECT t.`Folio Number`,
MAX(t.`Closing Date`) AS LatestClosing,
(SELECT
s.`Closing Date`
FROM MLSFinalimport s
WHERE t.`Folio Number` = s.`Folio Number`
ORDER BY s.`Closing Date` DESC
LIMIT 1, 1) AS FirstClosing,
FROM MLSFinalimport t
GROUP BY t.`Folio Number`) SubQuery) SubQuery
This is generating a result that looks like this:
LatestClosing First Closing numofdays
7/20/2016 5/9/2006 3725
This is what I need. However, I'm stuck trying to add the original column for each row called "Folio Number". How do I proceed?
Thank you very much.
Pros for MySQL at this? Probably the opposite.. MySQL doesn't support window functions so you can try using a correlated query with LIMIT/OFFSET:
SELECT p.folio,p.max_d,p.second_d,DATEDIFF(p.max_d,p.second_d) as NumOfDays
FROM (
SELECT t.folio,MAX(t.date) as max_d,
(SELECT s.date FROM YourTable s
WHERE t.folio = s.folio
ORDER BY s.date DESC
LIMIT 1,1) as second_d
FROM YourTable t
GROUP BY t.folio) p

MySQL Conditional count based on a value in another column

I have table that looks like this:
id rank
a 2
a 1
b 4
b 3
c 7
d 1
d 1
e 9
I need to get all the distinct rank values on one column and count of all the unique id's that have reached equal or higher rank than in the first column.
So the result I need would be something like this:
rank count
1 5
2 4
3 3
4 3
7 2
9 1
I've been able to make a table with all the unique id's with their max rank:
SELECT
MAX(rank) AS 'TopRank',
id
FROM myTable
GROUP BY id
I'm also able to get all the distinct rank values and count how many id's have reached exactly that rank:
SELECT
DISTINCT TopRank AS 'rank',
COUNT(id) AS 'count of id'
FROM
(SELECT
MAX(rank) AS 'TopRank',
id
FROM myTable
GROUP BY id) tableDerp
GROUP BY TopRank
ORDER BY TopRank ASC
But I don't know how to get count of id's where the rank is equal OR HIGHER than the rank in column 1. Trying SUM(CASE WHEN TopRank > TopRank THEN 1 END) naturally gives me nothing. So how can I get the count of id's where the TopRank is higher or equal to each distinct rank value? Or am I looking in the wrong way and should try something like running totals instead? I tried to look for similar questions but I think I'm completely on a wrong trail here since I couldn't find any and this seems a pretty simple problem that I'm just overthinking somehow. Any help much appreciated.
One approach is to use a correlated subquery. Just get the list of ranks and then use a correlated subquery to get the count you are looking for:
SELECT r.rank,
(SELECT COUNT(DISTINCT t2.id)
FROM myTable t2
WHERE t2.rank >= r.rank
) as cnt
FROM (SELECT DISTINCT rank FROM myTable) r;

How can I write a query that aggregate a single row with latest date among multiple set of rows?

I have a MySQL table where there are many rows for each person, and I want to write a query which aggregates rows with special constraint. (one per person)
For example, lets say the table is consist of following data.
name date reason
---------------------------------------
John 2013-04-01 14:00:00 Vacation
John 2013-03-31 18:00:00 Sick
Ted 2012-05-06 20:00:00 Sick
Ted 2012-02-20 01:00:00 Vacation
John 2011-12-21 00:00:00 Sick
Bob 2011-04-02 20:00:00 Sick
I want to see the distribution of 'reason' column. If I just write a query like below
select reason, count(*) as count from table group by reason
then I will be able to see number of reasons for this table overall.
reason count
------------------
Sick 4
Vacation 2
However, I am only interested in single reason from each person. The reason that should be counted should be from a row with latest date from the person's records. For example, John's latest reason would be Vacation while Ted's latest reason would be Sick. And Bob's latest reason (and the only reason) is Sick.
The expected result for that query should be like below. (Sum of count will be 3 because there are only 3 people)
reason count
-----------------
Sick 2
Vacation 1
Is it possible to write a query such that single latest reason will be counted when I want to see distribution(count) of reasons?
Here are some facts about the table.
The table has tens of millions of rows
For most of times, each person has one reason.
Some people have multiple reasons, but 99.99% of people have fewer than 5 reasons.
There are about 30 different reasons while there are millions of distinct names.
The table is partitioned based on date range.
SELECT T.REASON, COUNT(*)
FROM
(
SELECT PERSON, MAX(DATE) AS MAX_DATE
FROM TABLE-NAME
GROUP BY PERSON
) A, TABLE-NAME T
WHERE T.PERSON = A.PERSON AND T.DATE = A.MAX_DATE
GROUP BY T.REASON
Try this
select reason, count(*) from
(select reason from table where date in
(select max(date) from table group by name)) t
group by reason
In MySQL, it's not very efficient to do this kind of query since you don't have access to tools like partitionning query in SQL Server or Oracle.
You can still emulate it by doing a subquery and retrieve the rows based on the condition you need, here the maximum date :
SELECT t.reason, COUNT(1)
FROM
(
SELECT name, MAX(adate) AS maxDate
FROM #aTable
GROUP BY name
) maxDateRows
INNER JOIN #aTable t ON maxDateRows.name = t.name
AND maxDateRows.maxDate = t.adate
GROUP BY t.reason
You can see a sample here.
Test this query on your samples, but I'm afraid that it will be slow as hell.
For your information, you can do the same thing in a more elegant and much much faster way in SQL Server :
SELECT reason, COUNT(1)
FROM
(
SELECT name
, reason
, RANK() OVER(PARTITION BY name ORDER BY adate DESC) as Rank
FROM #aTable
) AS rankTable
WHERE Rank = 1
GROUP BY reason
The sample is here
If you are really stuck to MySql, and the first query is too slow, then you can split the problem.
Do a first query creating a table:
CREATE TABLE maxDateRows AS
SELECT name, MAX(adate) AS maxDate
FROM #aTable
GROUP BY name
Then create index on both name and maxDate.
Finally, get the results :
SELECT t.reason, COUNT(1)
FROM maxDateRows m
INNER JOIN #aTable t ON m.name = t.name
AND m.maxDate = t.adate
GROUP BY t.reason
The solution you are looking for seems to be solved by this query :
select
reason,
count(*)
from (select * from tablename group by name) abc
group by
reason
It is quite fast and simple. You can view the SQL Fiddle
Apologies if this answer duplicates an existing. Maybe I'm suffering from some form aphasia but I cannot see it...
SELECT x.reason
, COUNT(*)
FROM absentism x
JOIN
( SELECT name,MAX(date) max_date FROM absentism GROUP BY name) y
ON y.name = x.name
AND y.max_date = x.date
GROUP
BY reason;