SELECT rows with the second highest value in a column [duplicate] - mysql

This question already has answers here:
What is the simplest SQL Query to find the second largest value?
(46 answers)
Closed 2 years ago.
Let's say I have a table similar to the following:
Item Description Time
----- ----------- -----
ItemA1 descript 08-16-2013 00:00:00
ItemA2 descript 08-16-2013 00:00:00
ItemA3 descript 08-16-2013 00:00:00
.
.
ItemAN descript 08-16-2013 00:00:00
ItemB1 descript 08-13-2013 00:00:00
ItemB2 descript 08-13-2013 00:00:00
ItemB3 descript 08-13-2013 00:00:00
.
.
ItemBN descript 08-13-2013 00:00:00
.
.
.
ItemX1 descript 01-13-2012 00:00:00
ItemX2 descript 01-13-2012 00:00:00
ItemX3 descript 01-13-2012 00:00:00
.
.
ItemXN descript 01-13-2012 00:00:00
Groups of items are added periodically. When a group of items is added they are all added with the same "Time" field. "Time" essentially serves as a unique index for that item group.
I want to SELECT the group of items that have the second highest time. In this example my query should pull the "B" items. I know I can do max(time) to SELECT the "A" items, but I don't know how I would do second last.
My "Time" columns are stored as TIMESTAMP if that means anything.

You can try something like:
SELECT MAX(Time)
FROM yourTable
WHERE Time < (SELECT MAX(Time) FROM yourTable)
SQLFiddle Demo

One approach:
SELECT t.*
FROM mytable t
JOIN ( SELECT l.time
FROM mytable l
GROUP BY l.time
ORDER BY l.time DESC
LIMIT 1,1
) m
ON m.time = t.time
This uses an inline view (assigned an alias of m) to return the second "greatest" time value. The GROUP BY gets us a distinct list, the ORDER BY DESC puts the latest first, and the "trick" is the LIMIT, which returns the second row. LIMIT(m,n) = (skip first m rows, return next n rows)
With that time value, we can join back to the original table, to get all rows that have a matching time value.
Performance will be enhanced with an index with leading column of time. (I think MySQL should be able to avoid a "Using filesort" operation, and get the result from the inline view query fairly quickly.)
But, including a predicate in the inline view query, if you "know" that the second latest time will never be more than a certain number of days old, won't hurt performance:
WHERE l.time > NOW() + INTERVAL -30 DAYS
But with that added, then the query won't return the "second latest" group if it's time is more than 30 days ago.
The SELECT MAX(time) WHERE time < ( SELECT MAX(time) approach to get the second latest (the approach given in other answers) might be faster, especially if there is no index with leading column of time, but performance would best be gauged by actual testing. The index with leading column of time will speed up the MAX() approach as well.)
The query I provided can be easily extended to get the 4th latest, 42nd latest, etc, by changing the LIMIT clause... LIMIT(3,1), LIMIT(41,1), etc.

This should give you second biggest time:
SELECT time FROM table GROUP BY time ORDER BY time DESC LIMIT 1,1

SELECT T1.ITEM
FROM YOURTABLE T1
WHERE T1.TIME = ( SELECT MAX(T2.TIME)
FROM YOURTABLE T2
WHERE T2.TIME < ( SELECT MAX(T3.TIME)
FROM YOURTABLE T3
)
)

Get second, third, fourth......Nth highest value using following query:
SELECT MIN(value) from yourTable WHERE value IN( SELECT TOP N value FROM yourTable ORDER BY value DESC)
Replace N by you number i.e. N=2 for second highest value, N=3 for third highest value and so on. So for second highest value use:
SELECT MIN(value) from yourTable WHERE value IN( SELECT TOP 2 value FROM yourTable ORDER BY value DESC)

Something really straightforward like this should work
select * from my-table where time =
(Select top 1 time
from (select top 2 time from my-table order by time desc)
order by time asc)

Here is another solution which I think should work for your problem:
CREATE TEMPORARY TABLE xHighest AS (SELECT DISTINCT Time FROM `my-table` ORDER BY Time DESC LIMIT 1,1);
SELECT * FROM `my-table` JOIN xHighest ON (my-table.Time = xHighest.Time);
You can choose if second, third, ... highest value should be used by changing the first parameter of LIMIT.

MYSQL: limit base solution
Example: records 1, 2, 3, 4, 5.
LIMIT 2,1 means it will return 3rd highest number, as LIMIT 1,1 return 2nd highest number and so on
SELECT rc.rc_officer_id FROM recovery_complain_officer rc ORDER BY rc.rc_officer_id DESC LIMIT 2,1

Leftfield-ish answer, but this allows you to select n-1 ordered values from a single table as you want (credit to the https://stackoverflow.com/a/35234692/618320 answer by #Uueerdo), with nearly no extra cost.
You can use GROUP_CONCAT(DISTINCT...), followed by some SUBSTRING(...),
SELECT
SUBSTRING_INDEX(groupTime, ',', 1) AS time1,
SUBSTRING_INDEX(SUBSTRING_INDEX(groupTime, ',', 2), ',', -1) AS time2,
SUBSTRING_INDEX(SUBSTRING_INDEX(groupTime, ',', 3), ',', -1) AS time3
FROM (
SELECT GROUP_CONCAT(DISTINCT Time ORDER BY Time DESC) groupTime FROM mytable) t
The inner query would give you a single-row result back like "08-16-2013 00:00:00,08-13-2013 00:00:00,01-13-2012 00:00:00", and splitting that string up the way we are doing, gives you a table result like,
time1 time2 time3
--------- ------------ ------------
08-16-2013 00:00:00 08-13-2013 00:00:00 01-13-2012 00:00:00

Maybe TOP and START AT can help here.
I have used this in Sybase SQL.
SELECT TOP 1 START AT 2 * FROM Table_Name ORDER BY CREATEDDATETIME DESC;

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.

Select full row containing max value for each day [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 4 years ago.
My table has the following structure:
sensor_id | timestamp | value
-----------|------------|-------
1 | 1516905900 | 100.1
4 | 1516916920 | 90.4
... | ... | ...
I need to select the columns with the max value for each day for a given sensor_id. I need the timestamp associated with each max value in the results.
I have had some success using MAX() and GROUP BY and DATE_FORMAT, but I cannot get my query to include the timestamp associated with the max value for each group.
This is what I have so far:
select DATE_FORMAT(from_unixtime(timestamp), '%m/%d/%Y') as x, max(value) from sensor_log where sensor_id=6 group by x;
The result only includes the x and max(value) columns. I think it might be possible to use some sort of JOIN to get the rest of the columns, but I haven't been able to figure it out.
Another issue I can foresee is the possibility of a sensor_id having multiple occurrences of the max value on the same day, in this case I would only like to keep the first occurrence of that value for that day.
Hmmm. This sounds like a good use of a correlated subquery with a twist:
select date(from_unixtime(sl.timestamp)) as dte, sl.sensor_id, sl.value, sl.timestamp
from sensor_log sl
where sl.timestamp = (select sl2.timestamp
from sensor_log sl2
where sl2.sensor_id = sl.sensor_id and
date(from_unixtime(sl2.timestamp)) = date(from_unixtime(sl.timestamp))
order by sl2.value desc, sl.timestamp asc
limit 1
);
Starting with MySQL version 8, this can be accomplished with a ranking function dense_rank.
select sensor_id,timestamp,value,DATE_FORMAT(from_unixtime(timestamp),'%m/%d/%Y') as dt
from (select t.*
,dense_rank() over(partition by DATE_FORMAT(from_unixtime(timestamp),'%m/%d/%Y') order by value desc) as rnk
from tbl t
) t
where rnk=1

In ColdFusion how to Convert LIMIT function query in MY SQL to MS SQL Server 2012 [duplicate]

This question already has answers here:
Implement paging (skip / take) functionality with this query
(6 answers)
Closed 1 year ago.
I have this query with MySQL:
select * from table1 LIMIT 10,20
How can I do this with SQL Server?
Starting SQL SERVER 2005, you can do this...
USE AdventureWorks;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
FROM Sales.SalesOrderHeader
)
SELECT *
FROM OrderedOrders
WHERE RowNumber BETWEEN 10 AND 20;
or something like this for 2000 and below versions...
SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC
Starting with SQL SERVER 2012, you can use the OFFSET FETCH Clause:
USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
ORDER BY SalesOrderID
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
GO
http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx
This may not work correctly when the order by is not unique.
If the query is modified to ORDER BY OrderDate, the result set returned is not as expected.
This is how I limit the results in MS SQL Server 2012:
SELECT *
FROM table1
ORDER BY columnName
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
NOTE: OFFSET can only be used with or in tandem to ORDER BY.
To explain the code line OFFSET xx ROWS FETCH NEXT yy ROW ONLY
The xx is the record/row number you want to start pulling from in the table, i.e: If there are 40 records in table 1, the code above will start pulling from row 10.
The yy is the number of records/rows you want to pull from the table.
To build on the previous example: If table 1 has 40 records and you began pulling from row 10 and grab the NEXT set of 10 (yy).
That would mean, the code above will pull the records from table 1 starting at row 10 and ending at 20. Thus pulling rows 10 - 20.
Check out the link for more info on OFFSET
This is almost a duplicate of a question I asked in October:
Emulate MySQL LIMIT clause in Microsoft SQL Server 2000
If you're using Microsoft SQL Server 2000, there is no good solution. Most people have to resort to capturing the result of the query in a temporary table with a IDENTITY primary key. Then query against the primary key column using a BETWEEN condition.
If you're using Microsoft SQL Server 2005 or later, you have a ROW_NUMBER() function, so you can get the same result but avoid the temporary table.
SELECT t1.*
FROM (
SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN #offset+1 AND #offset+#count;
You can also write this as a common table expression as shown in #Leon Tayson's answer.
SELECT *
FROM (
SELECT TOP 20
t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
FROM table1 t
ORDER BY
field1
) t
WHERE rn > 10
Syntactically MySQL LIMIT query is something like this:
SELECT * FROM table LIMIT OFFSET, ROW_COUNT
This can be translated into Microsoft SQL Server like
SELECT * FROM
(
SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum
FROM table
) a
WHERE rnum > OFFSET
Now your query select * from table1 LIMIT 10,20 will be like this:
SELECT * FROM
(
SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum
FROM table1
) a
WHERE rnum > 10
SELECT TOP 10 * FROM table;
Is the same as
SELECT * FROM table LIMIT 0,10;
Here's an article about implementing Limit in MsSQL Its a nice read, specially the comments.
This is one of the reasons I try to avoid using MS Server... but anyway. Sometimes you just don't have an option (yei! and I have to use an outdated version!!).
My suggestion is to create a virtual table:
From:
SELECT * FROM table
To:
CREATE VIEW v_table AS
SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table
Then just query:
SELECT * FROM v_table WHERE row BETWEEN 10 AND 20
If fields are added, or removed, "row" is updated automatically.
The main problem with this option is that ORDER BY is fixed. So if you want a different order, you would have to create another view.
UPDATE
There is another problem with this approach: if you try to filter your data, it won't work as expected. For example, if you do:
SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20
WHERE becomes limited to those data which are in the rows between 10 and 20 (instead of searching the whole dataset and limiting the output).
In SQL there's no LIMIT keyword exists. If you only need a limited number of rows you should use a TOP keyword which is similar to a LIMIT.
Must try. In below query, you can see group by, order by, Skip rows, and limit rows.
select emp_no , sum(salary_amount) from emp_salary
Group by emp_no
ORDER BY emp_no
OFFSET 5 ROWS -- Skip first 5
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows
Easy way
MYSQL:
SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'
MSSQL:
SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset'
ROWS FETCH NEXT 'per_page' ROWS ONLY
ORDER BY is mandatory
This is a multi step approach that will work in SQL2000.
-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)
INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria
Select * FROM #foo where rowID > 10
SELECT
*
FROM
(
SELECT
top 20 -- ($a) number of records to show
*
FROM
(
SELECT
top 29 -- ($b) last record position
*
FROM
table -- replace this for table name (i.e. "Customer")
ORDER BY
2 ASC
) AS tbl1
ORDER BY
2 DESC
) AS tbl2
ORDER BY
2 ASC;
-- Examples:
-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;
-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;
-- To calculate $b:
-- $b = ($a + position) - 1
-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;
If your ID is unique identifier type or your id in table is not sorted you must do like this below.
select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5
The code will be
select * from limit 2,5
better use this in MSSQLExpress 2017.
SELECT * FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;
--Giving a Column [Count] and assigning every row a unique counting without ordering something then re select again where you can provide your limits.. :)
One of the possible way to get result as below , hope this will help.
declare #start int
declare #end int
SET #start = '5000'; -- 0 , 5000 ,
SET #end = '10000'; -- 5001, 10001
SELECT * FROM (
SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
) a WHERE a.row > #start and a.row <= #end
If i remember correctly (it's been a while since i dabbed with SQL Server) you may be able to use something like this: (2005 and up)
SELECT
*
,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20

mysql moving average of N rows

I have a simple MySQL table like below, used to compute MPG for a car.
+-------------+-------+---------+
| DATE | MILES | GALLONS |
+-------------+-------+---------+
| JAN 25 1993 | 20.0 | 3.00 |
| FEB 07 1993 | 55.2 | 7.22 |
| MAR 11 1993 | 44.1 | 6.28 |
+-------------+-------+---------+
I can easily compute the Miles Per Gallon (MPG) for the car using a select statement, but because the MPG varies widely from fillup to fillup (i.e. you don't fill the exact same amount of gas each time), I would like to computer a 'MOVING AVERAGE' as well. So for any row the MPG is MILES/GALLON for that row, and the MOVINGMPG is the SUM(MILES)/SUM(GALLONS) for the last N rows. If less than N rows exist by that point, just SUM(MILES)/SUM(GALLONS) up to that point.
Is there a single SELECT statement that will fetch the rows with MPG and MOVINGMPG by substituting N into the select statement?
Yes, it's possible to return the specified resultset with a single SQL statement.
Unfortunately, MySQL does not support analytic functions, which would make for a fairly simple statement. Even though MySQL does not have syntax to support them, it is possible to emulate some analytic functions using MySQL user variables.
One of the ways to achieve the specified result set (with a single SQL statement) is to use a JOIN operation, using a unique ascending integer value (rownum, derived by and assigned within the query) to each row.
For example:
SELECT q.rownum AS rownum
, q.date AS latest_date
, q.miles/q.gallons AS latest_mpg
, COUNT(1) AS cnt_rows
, MIN(r.date) AS earliest_date
, SUM(r.miles) AS rtot_miles
, SUM(r.gallons) AS rtot_gallons
, SUM(r.miles)/SUM(r.gallons) AS rtot_mpg
FROM ( SELECT #s_rownum := #s_rownum + 1 AS rownum
, s.date
, s.miles
, s.gallons
FROM mytable s
JOIN (SELECT #s_rownum := 0) c
ORDER BY s.date
) q
JOIN ( SELECT #t_rownum := #t_rownum + 1 AS rownum
, t.date
, t.miles
, t.gallons
FROM mytable t
JOIN (SELECT #t_rownum := 0) d
ORDER BY t.date
) r
ON r.rownum <= q.rownum
AND r.rownum > q.rownum - 2
GROUP BY q.rownum
Your desired value of "n" to specify how many rows to include in each rollup row is specified in the predicate just before the GROUP BY clause. In this example, up to "2" rows in each running total row.
If you specify a value of 1, you will get (basically) the original table returned.
To eliminate any "incomplete" running total rows (consisting of fewer than "n" rows), that value of "n" would need to be specified again, adding:
HAVING COUNT(1) >= 2
sqlfiddle demo: http://sqlfiddle.com/#!2/52420/2
Followup:
Q: I'm trying to understand your SQL statement. Does your solution do a select of twenty rows for each row in the db? In other words, if I have 1000 rows will your statement perform 20000 selects? (I'm worried about performance)...
A: You are right to be concerned with performance.
To answer your question, no, this does not perform 20,000 selects for 1,000 rows.
The performance hit comes from the two (essentially identical) inline views (aliased as q and r). What MySQL does with these (basically) is create temporary MyISAM tables (MySQL calls them "derived tables"), which are basically copies of mytable, with an extra column, each row assigned a unique integer value from 1 to the number of rows.
Once the two "derived" tables are created and populated, MySQL runs the outer query, using those two "derived" tables as a row source. Each row from q, is matched with up to n rows from r, to calculate the "running total" miles and gallons.
For better performance, you could use a column already in the table, rather than having the query assign unique integer values. For example, if the date column is unique, then you could calculate "running total" over a certain period of days.
SELECT q.date AS latest_date
, SUM(q.miles)/SUM(q.gallons) AS latest_mpg
, COUNT(1) AS cnt_rows
, MIN(r.date) AS earliest_date
, SUM(r.miles) AS rtot_miles
, SUM(r.gallons) AS rtot_gallons
, SUM(r.miles)/SUM(r.gallons) AS rtot_mpg
FROM mytable q
JOIN mytable r
ON r.date <= q.date
AND r.date > q.date + INTERVAL -30 DAY
GROUP BY q.date
(For performance, you would want an appropriate index defined with date as a leading column in the index.)
For the first query, any predicates included (in the inline view definition queries) to reduce the number of rows returned (for example, return only date values in the past year) would reduce the number of rows to be processed, and would also likely improve performance.
Again, to your question about running 20,000 selects for 1,000 rows... a nested loops operation is another way to get the same result set. For a large number of rows, this can exhibit slower performance. (On the other hand, this approach can be fairly efficient, when only a few rows are being returned:
SELECT q.date AS latest_date
, q.miles/q.gallons AS latest_mpg
, ( SELECT SUM(r.miles)/SUM(r.gallons)
FROM mytable r
WHERE r.date <= q.date
AND r.date >= q.date + INTERVAL -90 DAY
) AS rtot_mpg
FROM mytable q
ORDER BY q.date
Something like this should work:
SELECT Date, Miles, Gallons, Miles/Gallons as MilesPerGallon,
#Miles:=#Miles+Miles overallMiles,
#Gallons:=#Gallons+Gallons overallGallons,
#RunningTotal:=#Miles/#Gallons runningTotal
FROM YourTable
JOIN (SELECT #Miles:= 0) t
JOIN (SELECT #Gallons:= 0) s
SQL Fiddle Demo
Which produces the following:
DATE MILES GALLONS MILESPERGALLON RUNNINGTOTAL
January, 25 1993 20 3 6.666667 6.666666666667
February, 07 1993 55.2 7.22 7.645429 7.358121330724
March, 11 1993 44.1 6.28 7.022293 7.230303030303
--EDIT--
In response to the comment, you can add another Row Number to limit your results to the last N rows:
SELECT *
FROM (
SELECT Date, Miles, Gallons, Miles/Gallons as MilesPerGallon,
#Miles:=#Miles+Miles overallmiles,
#Gallons:=#Gallons+Gallons overallGallons,
#RunningTotal:=#Miles/#Gallons runningTotal,
#RowNumber:=#RowNumber+1 rowNumber
FROM (SELECT * FROM YourTable ORDER BY Date DESC) u
JOIN (SELECT #Miles:= 0) t
JOIN (SELECT #Gallons:= 0) s
JOIN (SELECT #RowNumber:= 0) r
) t
WHERE rowNumber <= 3
Just change your ORDER BY clause accordingly. And here is the updated fiddle.

ORDER BY date and time BEFORE GROUP BY name in mysql

i have a table like this:
name date time
tom | 2011-07-04 | 01:09:52
tom | 2011-07-04 | 01:09:52
mad | 2011-07-04 | 02:10:53
mad | 2009-06-03 | 00:01:01
i want oldest name first:
SELECT *
ORDER BY date ASC, time ASC
GROUP BY name
(->doesn't work!)
now it should give me first mad(has earlier date) then tom
but with GROUP BY name ORDER BY date ASC, time ASC gives me the newer mad first because it groups before it sorts!
again: the problem is that i can't sort by date and time before i group because GROUP BY must be before ORDER BY!
Another method:
SELECT *
FROM (
SELECT * FROM table_name
ORDER BY date ASC, time ASC
) AS sub
GROUP BY name
GROUP BY groups on the first matching result it hits. If that first matching hit happens to be the one you want then everything should work as expected.
I prefer this method as the subquery makes logical sense rather than peppering it with other conditions.
As I am not allowed to comment on user1908688's answer, here a hint for MariaDB users:
SELECT *
FROM (
SELECT *
ORDER BY date ASC, time ASC
LIMIT 18446744073709551615
) AS sub
GROUP BY sub.name
https://mariadb.com/kb/en/mariadb/why-is-order-by-in-a-from-subquery-ignored/
I think this is what you are seeking :
SELECT name, min(date)
FROM myTable
GROUP BY name
ORDER BY min(date)
For the time, you have to make a mysql date via STR_TO_DATE :
STR_TO_DATE(date + ' ' + time, '%Y-%m-%d %h:%i:%s')
So :
SELECT name, min(STR_TO_DATE(date + ' ' + time, '%Y-%m-%d %h:%i:%s'))
FROM myTable
GROUP BY name
ORDER BY min(STR_TO_DATE(date + ' ' + time, '%Y-%m-%d %h:%i:%s'))
This worked for me:
SELECT *
FROM your_table
WHERE id IN (
SELECT MAX(id)
FROM your_table
GROUP BY name
);
Use a subselect:
select name, date, time
from mytable main
where date + time = (select min(date + time) from mytable where name = main.mytable)
order by date + time;
If you wont sort by max date and group by name, you can do this query:
SELECT name,MAX(date) FROM table group by name ORDER BY name
where date may by some date or date time string. It`s response to you max value of date by each one name
Another way to solve this would be with a LEFT JOIN, which could be more efficient. I'll first start with an example that considers only the date field, as probably it is more common to store date + time in one datetime column, and I also want to keep the query simple so it's easier to understand.
So, with this particular example, if you want to show the oldest record based on the date column, and assuming that your table name is called people you can use the following query:
SELECT p.* FROM people p
LEFT JOIN people p2 ON p.name = p2.name AND p.date > p2.date
WHERE p2.date is NULL
GROUP BY p.name
What the LEFT JOIN does, is when the p.date column is at its minimum value, there will be no p2.date with a smaller value on the left join and therefore the corresponding p2.date will be NULL. So, by adding WHERE p2.date is NULL, we make sure to show only the records with the oldest date.
And similarly, if you want to show the newest record instead, you can just change the comparison operator in the LEFT JOIN:
SELECT p.* FROM people p
LEFT JOIN people p2 ON p.name = p2.name AND p.date < p2.date
WHERE p2.date is NULL
GROUP BY p.name
Now, for this particular example where date+time are separate columns, you would need to add them in some way if you want to query based on the datetime of two columns combined, for example:
SELECT p.* FROM people p
LEFT JOIN people p2 ON p.name = p2.name AND p.date + INTERVAL TIME_TO_SEC(p.time) SECOND > p2.date + INTERVAL TIME_TO_SEC(p2.time) SECOND
WHERE p2.date is NULL
GROUP BY p.name
You can read more about this (and also see some other ways to accomplish this) on the The Rows Holding the Group-wise Maximum of a Certain Column page.
I had a different variation on this question where I only had a single DATETIME field and needed a limit after a group by or distinct after sorting descending based on the datetime field, but this is what helped me:
select distinct (column) from
(select column from database.table
order by date_column DESC) as hist limit 10
In this instance with the split fields, if you can sort on a concat, then you might be able to get away with something like:
select name,date,time from
(select name from table order by concat(date,' ',time) ASC)
as sorted
Then if you wanted to limit you would simply add your limit statement to the end:
select name,date,time from
(select name from table order by concat(date,' ',time) ASC)
as sorted limit 10
In Oracle, This work for me
SELECT name, min(date), min(time)
FROM table_name
GROUP BY name
work for me mysql
select * from (SELECT number,max(date_added) as datea FROM sms_chat group by number) as sup order by datea desc
This is not the exact answer, but this might be helpful for the people looking to solve some problem with the approach of ordering row before group by in mysql.
I came to this thread, when I wanted to find the latest row(which is order by date desc but get the only one result for a particular column type, which is group by column name).
One other approach to solve such problem is to make use of aggregation.
So, we can let the query run as usual, which sorted asc and introduce new field as max(doc) as latest_doc, which will give the latest date, with grouped by the same column.
Suppose, you want to find the data of a particular column now and max aggregation cannot be done.
In general, to finding the data of a particular column, you can make use of GROUP_CONCAT aggregator, with some unique separator which can't be present in that column, like GROUP_CONCAT(string SEPARATOR ' ') as new_column, and while you're accessing it, you can split/explode the new_column field.
Again, this might not sound to everyone. I did it, and liked it as well because I had written few functions and I couldn't run subqueries. I am working on codeigniter framework for php.
Not sure of the complexity as well, may be someone can put some light on that.
Regards :)