MySQL Select max() from every Value - mysql

I there a way to get the max() Value of every Value?
I have a table like this:
id primary key
name foreign key
age
and I need the highes age of every Name. For example:
ID NAME AGE
1, Marco, 12
2, Jason, 23
3, Tom, 5
4, Marco, 16
5, Jason, 22
The output should be:
ID NAME AGE
2, Jason, 23
3, Tom, 5
4, Marco, 16
Is this possible and how?
Thank you.

You can get the max value of each column using aggregation:
select max(id), name, max(age)
from t
group by name;
But if you want the complete row with the max age, then that would be:
select t.*
from t
where t.age = (select max(t2.age) from t t2 where t2.name = t.name);

Try this:
select id,name,max(age) over(partition by name) as max_age from table group by id,name;

You can use aggregation:
select min(id) id, name, max(age) age from mytable group by name

You can get the max age and name from sub query then left join to obtain its ID.
SELECT b.id, a.name, a.maxage
FROM (SELECT name, MAX(age) AS maxage
FROM table
GROUP BY NAME
) a
LEFT JOIN table b ON a.NAME = b.NAME AND a.maxage= b.AGE

Related

MySql: How to select rows where all values are the same?

I have a table like this:
name |id | state
name1 12 4
name1 12 4
name2 33 3
name2 33 4
...
I want to select every name and id from table where state is only 4, that means name1 is correct, because it only has two records with state 4 and nothing more. Meanwhile name2 is wrong, because it has record with state 4 and record with state 3.
You can use aggregation as shown below:
SELECT name, id
FROM your_table
GROUP BY name, id
HAVING SUM(state<>4)=0;
See a Demo on SQL Fiddle.
select name, id from mytable where id not in
(select distinct id from mytable where state <> 4)
you might need 2 sub queries .
select with group by name were state 4
select with group by name
compare the count if the count is same then select it
example : select name , count (name) from table where state = 4 as T1
select name , count (name) from table as T2
select T1.name from T1 and T2 where T2.count = T1.count
You can use not exists like this:
select distinct name, id
from table1 a
where not exists (select *
from table1 b
where a.id=b.id and state<>4)
In a more general case you can use count distinct (with not exists or with a join):
select distinct name, id
from table1 a
where not exists (
select *
from table1 b
where a.id=b.id
group by id
HAVING count(distinct state)>1)

SELECT from external data in MySQL

Let's consider a made up example
SELECT id, name, score.score FROM
someTable,
(select someTableId, count(*) as score FROM SecondTable GROUP BY someTableId) as score
WHERE score.someTableId == id
ORDER BY score.score DESC
Let's now assume that I have a backend computing my scoring, and that I would like to remove the subquery and insert my own data instead. I would like to know how to do this.
I would like to do something like (this is the question, because what's below doesn't work):
SELECT id, name, score.score FROM
someTable,
((12,324), (1, 342)) as score(id, score)
WHERE score.someTableId == id
ORDER BY score.score DESC
Here is an example of external data substitution to a subquery:
SELECT * FROM users WHERE id IN (SELECT user_id FROM posts WHERE thread_id = 12 GROUP BY user_id);
Without a subquery and with external data:
SELECT * FROM users WHERE id IN (1,2,3);
If I understood you correctly :
SELECT id, name, score.score FROM
someTable,
(SELECT 12 as someTableId,324 as score UNION ALL SELECT 1, 342 <UNION ALL....>) as score(id, score)
WHERE score.someTableId == id
ORDER BY score.score DESC
Thats the only way you can do it, it doesn't actually replace the the subquery, but it replace the select from the table and can improve performance if thats what you are looking for.
In MySQL you don't need to specify a from clause like a dummy table when you are just looking to fetch dummy data.
Other DBMS require a dummy table name (typically DUAL) but in MySQL it's rather straightforward:
SELECT 12 AS id, 324 AS score
UNION ALL SELECT 2, 65
UNION ALL SELECT 3, 598
UNION ALL SELECT 4, 244
You can use this as any other result-set.

SELECT MAX() and corresponding field in the same row

Here's my table A
orderID groupID nameID
1 grade A foo
2 grade A bar
3 grade A rain
1 grade B rain
2 grade B foo
3 grade B bar
1 grade C rain
2 grade C bar
3 grade C foo
Desired result:
rain
bar
foo
I need nameID of max(orderID) from each grade. I can get right orderID from each grade, but nameID always stays as the first.
Thanks a Lot!
Praveen gave the right query! Extra question under his answer
edit: I just fixed a mistake in my answer.
You are looking for something quite like:
select
orderID,
groupID,
nameID
from
A
where
concat(orderID,'-',groupId) in (select concat(max(orderID),'-',groupId) from A group by groupID)
edit: in regards to the extra question:
To put the list in order of nameId, just add to the query:
order by
nameID
Here is an appropriate query, using a correlated subquery:
select orderID, groupID, nameID
from A
where orderId = (select max(OrderId) from A a2 where A.groupId = a2.groupId);
If you want to do this with aggregation, you can use the group_concat()/substring_index() trick:
SELECT max(orderID) as orderID, groupId,
substring_index(group_concat(nameId order by orderId desc), ',', 1) as nameID
FROM A
GROUP BY groupID;
SELECT * FROM (select
max(`orderID`) as maxID, `groupID`, `nameID`
from
Table1
GROUP BY `groupID`, `nameID`
ORDER BY maxID desc) abc
GROUP BY GROUPID
Fiddle With my test data
Fiddle with your data

Getting the second max value of col2 while being grouped by col1

I'm facing a corner here...
The background:
TABLE myrecord (
id int # primary key
name varchar(32) # test name
d_when varchar(8) # date in yyyymmdd string format
)
Content:
id name d_when
100 Alan 20110201
101 Dave 20110304
102 Alan 20121123
103 Alan 20131001
104 Dave 20131002
105 Bob 20131004
106 Mike 20131101
In layman terms, I want to figure out who is a "returner" and when was his last (i.e., 'penultimate') visit.
something like the over enthusiastic:
SELECT SECOND_MAX(id), CORRESPONDING(d_when)
FROM myrecord
GROUP BY name
HAVING count(name)>1;
result expected:
101 Dave 20110304
102 Alan 20121123
I tried the following so far.
SELECT T1.id, t1.name, T1.d_when
FROM myrecord t1
WHERE id IN (SELECT MAX(id),
COUNT(id) cn
WHERE cn>1
ORDER BY d_when DESC)
but something is clearly not right here.
Here's one way...
SELECT x.*
FROM my_table x
JOIN my_table y
ON y.name=x.name
AND y.d_when >= x.d_when
GROUP
BY x.name
, x.d_when
HAVING COUNT(*) = 2;
why is the second last id necessary?
if it's not:
SELECT MAX(id), name, MAX(d_when)
FROM myrecord
GROUP BY name
HAVING count(name)>1
if it is:
SELECT name, max(id), max(d_when)
FROM myrecord
WHERE
-- get only the names that have more then one occurrence
name in (
SELECT name
FROM myrecord
GROUP BY name
HAVING COUNT(*) > 1
)
-- filter out the max id's
AND id NOT IN(
SELECT max(id)
FROM myrecord
GROUP BY name
)
GROUP BY name
or even better (thanks to #Andomar for the mention):
SELECT name, max(id), max(d_when)
FROM myrecord
WHERE
-- filter out the max id's, this will also filter out those with one record
AND id NOT IN(
SELECT max(id)
FROM myrecord
GROUP BY name
)
GROUP BY name
In MySQL, for retrieving all those who have made second visit and their second visited date.
Query:
SELECT *
FROM
(
SELECT
#ID:=CASE WHEN #Name <> Name THEN 1 ELSE #ID+1 END AS rn,
#Name:=Name AS Name,
ID, d_when
FROM
(SELECT ID, Name, d_when
FROM myrecord
ORDER BY Name asc, d_when asc
) rec1, (SELECT #ID:= 0) rec1_id, (SELECT #Name:= 0) rec1_nm
) rec
where rec.rn=2
Output:
rn Name ID d_when
2 Dave 104 20131002
2 Alan 102 20121123
Assuming the id column ascends over time, you can select the second-highest d_when per name like:
select name
, d_when
from YourTable yt1
where id in
(
select max(id)
from YourTable yt2
where id not in
(
select max(id)
from YourTable yt3
group by
name
)
group by
name
)
select * from
myrecord
where id in (
SELECT max(id)
FROM myrecord
WHERE id not in (SELECT MAX(id)
FROM myrecord
GROUP BY name
HAVING count(name)>1)
group by name )

Query for finding duplicates

I am having a table with following schema:
CUSTOMERS (id INT, name VARCHAR(10), height VARCHAR(10), weight INT)
id is the primary key. I want to find out rows in which people who are having exactly same name, same height and same weight. In other words, I want to find out duplicates with-respect-to name, height and weight.
Example table:
1, sam, 160, 100
2, ron, 167, 88
3, john, 150, 90
4, sam, 160, 100
5, rick, 158, 110
6, john, 150, 90
7, sam, 166, 110
Example Output:
Now since there are people with same name, same height and same weight:
sam (id=1), sam (id=4)
and
john (id=3), john (id=6)
I want to get these ids. It is also okay if I get only one id per match (i.e. id=1 from first match and id=3 from second match).
I am trying this query but not sure if it is correct or not.
SELECT id
FROM customers
GROUP BY name, height, weight
Try this (valid for sql server):
SELECT
t.NAME,
'Ids = '+
(
SELECT cast(Id as varchar)+','
FROM Customers c
WHERE c.NAME = t.NAME AND c.Weight = t.Weight AND c.Height = t.Height
FOR XML PATH('')
)
FROM
(
SELECT Name, height, weight
FROM Customers
GROUP BY Name, height, weight
HAVING COUNT(*) > 1
) t
OR
as you asked - only one Id per match
SELECT
t.NAME,
c.Id
FROM
(
SELECT Name, height, weight
FROM Customers
GROUP BY Name, height, weight
HAVING COUNT(*) > 1
) t
JOIN Customers c ON t.NAME AND c.Weight = t.Weight AND c.Height = t.Height
SELECT *
FROM customers C
INNER JOIN
(
SELECT name, height, weight
FROM customers
GROUP BY name, height, weight
HAVING COUNT(*) > 1
) X ON C.name = X.name AND C.height = X.height AND C.weight = X.weight
SELECT c.*
FROM customers c
JOIN (
SELECT name, height, weight
FROM
GROUP BY name, height, weight
HAVING count(*) > 1
) t ON c.name = t.name and c.height = t.height and c.weight = t.weight
you are on the right way:
SELECT min(id)
FROM customers
GROUP BY name, height, weight
HAVING COUNT(*) > 1
I don't know what you are using since you tagged several databases.
In Sql server you won't be able to select the id without putting it in the SELECT.
so if you want to select other fields besides the ones in the group clasue you can use PARTITION BY. Something like this:
SELECT id,
ROW_NUMBER() OVER(PARTITION BY c.name, c.height, c.weight ORDER BY c.name) AS DuplicateCount
FROM customers c
This will give you the ids of the duplicates that you have with the same name, height and weight.
I'm not sure that this is faster that the other solutions though, but, you can profile it and compare.
If it is okay to get only one id per match as you say, you are close to solution:
SELECT
min( id )
,name, height, weight --<-- oncly if you need/want
FROM customers
GROUP BY name, height, weight
HAVING count(*) > 1