MYSQL Sort by name and largest id [duplicate] - mysql

This question already has answers here:
How can I SELECT rows with MAX(Column value), PARTITION by another column in MYSQL?
(22 answers)
Closed 3 years ago.
I want to sort a table by name. These should not be alphabetic but the largest id. I have this table.
id name
---|-----|
1 | abc |
2 | abc |
3 | def |
4 | def |
5 | def |
6 | abc |
7 | abc |
8 | def |
That's what i need
id name
---|-----|
8 | def |
5 | def |
4 | def |
3 | def |
7 | abc |
6 | abc |
2 | abc |
1 | abc |
Does anyone have an idea?

This is really shouting for window-functions:
SELECT *
FROM your_table t
ORDER BY MAX(id) OVER (PARTITION BY name) DESC, id DESC
With your select from the comment under Barmar's answer:
SELECT *
FROM posts p, influencer i
WHERE p.i_name = i.i_name
ORDER BY MAX(p.p_id) OVER (PARTITION BY i.i_name) DESC, p.p_id DESC
Perhaps also have a look here: MySQL Manual

Join the table with a subquery that gets the largest ID for each name and order by that.
SELECT t1.*
FROM YourTable AS t1
JOIN (
SELECT name, MAX(id) AS maxid
FROM YourTable
GROUP BY name
) AS t2 ON t1.name = t2.name
ORDER BY maxid DESC, id DESC
If you have two tables, you can still join them with the subquery.
select p1.*, i.*
FROM posts AS p1
JOIN influencers AS i ON p1.i_name = i.i_name
JOIN (
SELECT i_name, MAX(p_id) AS maxid
FROM posts
GROUP BY i_name
) AS p2 ON p1.i_name = p2.i_name
ORDER BY p2.maxid DESC, p1.p_id DESC

Related

MySQL Output column based on value that corresponds with max ID

There are a lot of questions dealing with max values but I can't find any that relate to this issue.
ID | Company | Result
----------------------
1 | 1 | A
2 | 1 | C
3 | 1 | B <--
4 | 2 | C
5 | 2 | B
6 | 2 | A <!--
7 | 3 | C
8 | 3 | A
9 | 3 | B <--
I need to output the Companies whose last Result (based on ID) was "B".
To further complicate the issue, the $query will be used this:
select * from table where Company in ($query)
Any ideas? Thanks!
On MySQL 8+, here is a query you may try using analytic functions:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Company ORDER BY ID DESC) rn
FROM yourTable
)
SELECT ID, Company, Result
FROM cte
WHERE rn = 1 AND Result = 'B';
Demo
On earlier versions of MySQL, we can try joining to a subquery which finds the most recent record for each company:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT Company, MAX(ID) AS MAX_ID
FROM yourTable
GROUP BY Company
) t2
ON t1.Company = t2.Company AND
t1.ID = t2.MAX_ID
WHERE
t1.Result = 'B';
Demo

How to select the latest price for product? [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 4 years ago.
Here is my table:
+----+------------+-----------+---------------+
| id | product_id | price | date |
+----+------------+-----------+---------------+
| 1 | 4 | 2000 | 2019-02-10 |
| 2 | 5 | 1600 | 2019-02-11 |
| 3 | 4 | 850 | 2019-02-11 |
| 4 | 5 | 1500 | 2019-02-13 |
+----+------------+-----------+---------------+
I need to get a list of unique product ids that are the latest (newest, in other word, bigger date) ones. So this is the expected result:
+------------+-----------+---------------+
| product_id | price | date |
+------------+-----------+---------------+
| 4 | 850 | 2019-02-11 |
| 5 | 1500 | 2019-02-13 |
+------------+-----------+---------------+
Any idea how can I achieve that?
Here is my query:
SELECT id, product_id, price, MAX(date)
FROM tbl
GROUP BY product_id
-- ot selects the max `date` with random price like this:
+------------+-----------+---------------+
| product_id | price | date |
+------------+-----------+---------------+
| 4 | 2000 | 2019-02-11 |
| 5 | 1600 | 2019-02-13 |
+------------+-----------+---------------+
-- See? Prices are wrong
You could use a correlated subquery
select t1.* from table t1
where t1.date=( select max(date) from table t2
where t1.product_id=t2.product_id
)
Select *from
table1 t1
where (t1.product_id, t1.date) in
(select t2.product_id, max(t2.date)
from table1 t2
where t1.product_id = t2.product_id
)
Don't use a GROUP BY. Use a filter:
SELECT id, product_id, price, MAX(date)
FROM tbl
WHERE tbl.date = (SELECT MAX(t2.date)
FROM tbl t2
WHERE t2.product_id = tbl.product_id
);
With an index on (product_id, date), this is probably the fastest method.
If you can have duplicates on a given date, you can resolve them with:
SELECT id, product_id, price, MAX(date)
FROM tbl
WHERE tbl.id = (SELECT t2.id
FROM tbl t2
WHERE t2.product_id = tbl.product_id
ORDER BY t2.date DESC
LIMIT 1
);
My solution is with the analytic function first_value
SELECT distinct product_id,
first_value(price) over (partition by product_id order by date desc) last_price,
first_value(date) over (partition by product_id order by date desc) last_date
FROM tbl
Assuming that you are using a modern version of MySQL (8.0), you can use this:
select *
from (
SELECT id
, product_id
, price
, date
, row_number() over (partition by product_id order by date desc) rn
FROM tbl
) a
where rn = 1

Get second highest values from a table

I have a table like this:
+----+---------+------------+
| id | conn_id | read_date |
+----+---------+------------+
| 1 | 1 | 2010-02-21 |
| 2 | 1 | 2011-02-21 |
| 3 | 2 | 2011-02-21 |
| 4 | 2 | 2013-02-21 |
| 5 | 2 | 2014-02-21 |
+----+---------+------------+
I want the second highest read_date for particular 'conn_id's i.e. I want a group by on conn_id. Please help me figure this out.
Here's a solution for a particular conn_id :
select max (read_date) from my_table
where conn_id=1
and read_date<(
select max (read_date) from my_table
where conn_id=1
)
If you want to get it for all conn_id using group by, do this:
select t.conn_id, (select max(i.read_date) from my_table i
where i.conn_id=t.conn_id and i.read_date<max(t.read_date))
from my_table t group by conn_id;
Following answer should work in MSSQL :
select id,conn_id,read_date from (
select *,ROW_NUMBER() over(Partition by conn_id order by read_date desc) as RN
from my_table
)
where RN =2
There is an intresting article on use of rank functions in MySQL here : ROW_NUMBER() in MySQL
If your table design as ID - date matching (ie a big id always a big date), you can group by id, otherwise do the following:
$sql_max = '(select conn_id, max(read_date) max_date from tab group by 1) as tab_max';
$sql_max2 = "(select tab.conn_id,max(tab.read_date) max_date2 from tab, $sql_max
where tab.conn_id = tab_max.conn_id and tab.read_date < tab_max.max_date
group by 1) as tab_max2";
$sql = "select tab.* from tab, $sql_max2
where tab.conn_id = tab_max2.conn_id and tab.read_date = tab_max2.max_date2";

Mysql - Select at least one or select none

I have a table as so...
----------------------------------------
| id | name | group | number |
----------------------------------------
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 3 | james | 2 | 2 |
| 4 | steven | 2 | 5 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
----------------------------------------
I'm running a select like so:
SELECT * FROM table WHERE number IN (2,3);
The problem im trying to solve is that I want to only grab get results from groups that have 1 or more rows of each number. For instance the above query is returning id's 1-2-3-5-6, when I'd like the results to exclude id 3 since the group of '2' can only return 1 result for the number of '2' and not for BOTH 2 and 3, since there's no row with the number 3 for the group 2 i'd like it to not even select id 3 at all.
Any help would be great.
Try it this way
SELECT *
FROM table1 t
WHERE number IN(2, 3)
AND EXISTS
(
SELECT *
FROM table1
WHERE number IN(2, 3)
AND `group` = t.`group`
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
)
or
SELECT *
FROM table1 t JOIN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
) q
ON t.`group` = q.`group`;
or
SELECT *
FROM table1
WHERE `group` IN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
);
Sample output (for both queries):
| ID | NAME | GROUP | NUMBER |
|----|-------|-------|--------|
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
Here is SQLFiddle demo
On this, you can approach from a fun way with multiple joins for what you WANT qualified, OR, apply a prequery to get all qualified groups as others have suggested, but readability is a bit off for me..
Anyhow, here's an approach going through the table once, but with joins
select DISTINCT
T.id,
T.Name,
T.Group,
T.Number
from
YourTable T
Join YourTable T2
on T.Group = T2.Group AND T2.Group = 2
Join YourTable T3
on T.Group = T3.Group AND T3.Group = 3
where
T.Number IN ( 2, 3 )
So on the first record, it is pointing to by it's own group to the T2 group AND the T2 group is specifically a 2... Then again, but testing the group for the T3 instance and T3's group is a 3.
If it cant complete the join to either of the T2 or T3 instances, the record is done for consideration, and since indexes work great for joins like this, make sure you have one index for your NUMBER criteria, and another index on the (GROUP, NUMBER) for those comparisons and the next query sample...
If doing by more than this simple 2, but larger group, prequery qualified groups, then join to that
select
YT2.*
from
( select YT1.group
from YourTable YT1
where YT1.Number in (2, 3)
group by YT1.group
having count( DISTINCT YT1.group ) = 2 ) PreQualified
JOIN YourTable YT2
on PreQualified.group = YT2.group
AND YT2.Number in (2,3)
Maybe this,if I understand you
SELECT id FROM table WHERE `group` IN
(SELECT `group` FROM table WHERE number IN (2,3)
GROUP BY `group`
HAVING COUNT(DISTINCT number)=2)
SQL Fiddle
This will return all ids where BOTH numbers exist in a group.Remove DISTINCT if you want ids for groups where just one numbers is in.

Select Rows with maximum column value grouped by another column without nested select statement

I know that this is a duplicate of Select Rows with Maximum Column Value group by Another Column but I want to select rows that have the maximum column value,as group by another column , but without nested select statement, I know it can be done like this:
SELECT
T.Name,
T.Rank,
T.ID
FROM MyTable T
WHERE T.Rank = (
SELECT MAX( T1.Rank) FROM MyTable T1
WHERE T1.Name= T.Name
)
where ID,
Rank,
Name is the table schema, and I want to group by results by Name first, and then choose one row from each Name group, depending on which one has the highest Rank.
Attached is a sample of the table I want to select from
mysql> SELECT t1.nm, t1.rank,t1.id
FROM mytable t1
LEFT JOIN (
SELECT nm, max(rank) as top
FROM mytable t2
GROUP BY nm
) AS t2 ON t1.nm=t2.nm AND t1.rank = t2.top
WHERE t2.nm IS not NULL
ORDER BY nm;
+----+------+---------+
| nm | rank | id |
+----+------+---------+
| m | -1 | b7kjhsf |
| n | 13 | d3sf |
+----+------+---------+
2 rows in set (0.00 sec)
mysql> select * from mytable;
+----+------+----------+
| nm | rank | id |
+----+------+----------+
| n | 11 | asfd |
| n | 11 | bsf |
| n | 11 | zzasdfsf |
| n | 13 | d3sf |
| n | 11 | effesf |
| n | 10 | yxxgesf |
| n | 11 | bkhjusf |
| m | -1 | b7kjhsf |
| m | -4 | cdfgabsf |
+----+------+----------+
9 rows in set (0.00 sec)
As mentioned in the other answer, the only other alternative that I know of, is using Common Table Expressions:
;WITH CTE AS
(
T.Name,
T.Rank,
T.ID,
ROW_NUMBER() OVER
(PARTITION BY Name ORDER BY Rank DESC)
AS RowNumber
FROM MyTable
)
SELECT *
FROM CTE
WHERE RowNumber = 1
SELECT Name, Id, Rank FROM
(
SELECT T.Name, T.Id, T.Rank, RANK() OVER (PARTITION BY T.Name ORDER BY T.Rank DESC) = 1 AS NameRank
FROM MyTable T
)
WHERE NameRank = 1
Not sure whether you are just trying to exclude the nested select, and whether joining aginst a subselect would be acceptable. If so:-
SELECT
T.Name,
T.Rank,
T.ID
FROM MyTable T
INNER JOIN (SELECT Name, MAX(Rank) AS MaxRank FROM MyTable GROUP BY Name ) T1
ON T.Name = T1.Name
AND T.Rank = T1.MaxRank