How to get two max id from two different rows? - mysql

I have table customer table, i need get max ids from two different approvers with same request id
How can i implement this scenairo
Expected output.
id request_id approver_id
2 1 2
4 1 1
Thanks for your time

You can apply GROUP BY on your columns request_id & approver_id and then select MAX(id) to get your expected output as below-
SELECT MAX(id),request_id ,approver_id
FROM customer_approved
GROUP BY request_id,approver_id

One approach uses a join to a subquery to restrict to only the max rows you want:
SELECT ca1.id, ca1.request_id, ca1.approver_id
FROM customer_approved ca1
INNER JOIN
(
SELECT approver_id, MAX(id) AS max_id
FROM customer_approved
GROUP BY approver_id
) ca2
ON ca1.approver_id = ca2.approver_id AND
ca1.id = ca2.max_id;
Demo
If you are using MySQL 8+, then you may also use ROW_NUMBER here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY approver_id ORDER BY id DESC) rn
FROM customer_approved
)
SELECT id, request_id, approver_id
FROM cte
WHERE rn = 1;
Demo

Related

return max value for each group but when there is a tie, return one with lower id in MySQL

I am using MySQL 8.0
My table looks like this:
group user_id score
A 1 33
B 2 22
A 3 22
B 4 22
I want it to return
group user_id score
A 1 33
B 2 22
note that even though group B has same score user_id=2 is final winner since he/she has lower user_id
How to improve from below query...?
SELECT group, user_id, max(score)
from table
Thanks in advance!
#Ambleu you are on the right track using MAX(), but to do this you need to use it in addition to MIN(), and also use a sub query to get the MAX(score) like this:
SELECT `mt`.`group`,
MIN(`mt`.`user_id`) AS `user_id`,
`mt`.`score`
FROM `myTable` AS `mt`
JOIN (SELECT `group`,
MAX(`score`) AS `score`
FROM `myTable`
GROUP BY `group`) AS `der` ON `der`.`group` = `mt`.`group`
AND `der`.`score` = `mt`.`score`
GROUP BY `mt`.`group`, `mt`.`score`
Here are your tables and the solution query mocked up on db-fiddle.
If this doesn't get you what you need please let me know and I'll try to assist further.
In MySQL 8.0, I would recommend window functions:
select grp, user_id, score
fom (
select t.*,
row_number() over(partition by grp order by score desc, user_id) rn
from mytable t
) t
where rn = 1
Alternatively, you can use a correlated subquery for filtering:
select t.*
from mytable t
where user_id = (
select t1.user_id
from mytable t1
where t1.grp = t.grp
order by t1.score desc, t1.user_id limit 1
)
The second query would take advantage of an index on (grp, score desc, user_id).
Side note: group is a language keyword, hence a poor choice for a column name. I renamed it to grp in the queries.

Correlated subquery with row number count

I have a table as follows and what I want is to use get the initial row with least id of each uid group.
The table is as follows
_id uid type
1 a a
2 b bbb #satisfied
3 b ccc
4 b aaa #satisfied
5 a aaa #satisfied
6 b eee
I can already get the initial row using the following correlated subquery
SELECT *
FROM table
WHERE _id IN (
SELECT MIN(_id)
FROM table
WHERE type IN ('aaa','bbb')
GROUP BY uid
);
However, I want the 4th column shown the count of rows satisfied the condition (type IN ('aaa','bbb')), as cnt shown below:
_id uid type cnt
5 a aaa 1
2 b bbb 2
I think I can count this use several joins and then join the result to my code...But this is ugly...Is there any elegant way to achieve this...
You can try this:
SELECT t1.*, t2.cnt
FROM table t1 INNER JOIN (
SELECT MIN(_id) AS id, COUNT(_id) AS cnt
FROM table
WHERE type IN ('aaa','bbb')
GROUP BY uid
) t2 ON t1._id = t2.id
ORDER BY t1.uid
If you are running MySQL 8.0, you can just use window functions for this:
select _id, uid, type, cnt
from (
select
t.*,
count(*) over(partition by uid) cnt,
row_number() over(partition by uid order by _id) rn
from mytable t
where type in ('aaa', 'bbb')
) t
where rn = 1
You can do this without a subquery. In MySQL 8+, you can use this logic:
SELECT DISTINCT MIN(_id) OVER (PARTITION BY uid) as _id,
uid,
FIRST_VALUE(type) OVER (PARTITION BY uid ORDER BY _id) as type,
COUNT(*) OVER (PARTITION BY uid) as cnt
FROM table
WHERE type IN ('aaa', 'bbb');
Unfortunately, MySQL doesn't have a "first" aggregation function, but there is a trick if you like:
SELECT MIN(_id) as _id, uid,
SUBSTRING_INDEX(GROUP_CONCAT(type ORDER BY _id), ',', 1) as type,
COUNT(*) as cnt
FROM table
WHERE type IN ('aaa', 'bbb')
GROUP BY uid;

MYSQL - Group By / Order By not working

I have the following data inside a table:
id person_id item_id price
1 1 1 10
2 1 1 20
3 1 3 50
Now what I want to do is group by the item ID, select the id that has the highest value and take the price.
E.g. the sum would be: (20 + 50) and ignore the 10.
I am using the following:
SELECT SUM(`price`)
FROM
(SELECT id, person_id, item_id, price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
ORDER BY id DESC) x
GROUP BY item_id
However, this query is still adding (10 + 20 + 50), which is obviously not what I need to have.
Any ideas to where I am going wrong?
Here is what you are trying to achieve. First you need grouping in a subquery and not in outer query. In outer query you need only sum:
SELECT SUM(`price`)
FROM
(SELECT MAX(price) as price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
GROUP BY item_id) x
http://sqlfiddle.com/#!9/40803/5
SELECT SUM(t1.price)
FROM tbl t1
LEFT JOIN tbl t2
ON t1.person_id= t2.person_id
AND t1.item_id = t2.item_id
AND t1.id<t2.id
WHERE t1.person_id = 1
AND t2.id IS NULL;
I'm not sure if this is the only requirement you have. If so, try this.
SELECT SUM(price)
FROM
(SELECT MAX(price)
FROM table
WHERE person_id = 1
GROUP BY item_id)
First of all - you don't need the person table, because the other table already contains the person_id. So i removed it from the examples.
Your query returns a sum of prices for each item.
If you replace SELECT SUM(price) with SELECT item_id, SUM(price) you wil get
item_id SUM(`price`)
1 30
3 50
But that is not what you want. Neither is it what you wrote in the question " (10 + 20 + 50)".
Now replacing the first line with SELECT id, item_id, SUM(price) you will get one row for each item with the highest id.
id item_id price
2 1 20
3 3 50
This works because of the "undocumented feature" of MySQL, wich allows you to select columns that are not listed in the GROUP BY clause and get the first row from the subselect each group (each item in this case).
Now you only need to sum the price column in an additional outer select
SELECT SUM(price)
FROM (
SELECT id, item_id ,price
FROM (
SELECT id, person_id, item_id, price
FROM `table` tbl
WHERE tbl.person_id = 1
ORDER BY id DESC ) x
GROUP BY item_id
) y
However i do not recomend to use that "feature". While it still works on MySQL 5.6, you never know if that will work with newer versions. It already doesn't work on MariaDB.
Instead you can determite the MAX(id) for each item in an subselect, select only the rows with the determined ids and get the summed price of them.
SELECT SUM(`price`)
FROM `table` tbl
WHERE tbl.id IN (
SELECT MAX(tbl2.id)
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
)
Another solution (wich internaly does the same) is
SELECT SUM(`price`)
FROM `table` tbl
JOIN (
SELECT MAX(tbl2.id) as id
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
) x ON x.id = tbl.id
Alex's solution also works fine, if the groups (number of rows per person and item) are rather small.
You have used group by in main query, but it is on subquery like
SELECT id, person_id, item_id, SUM(`price`) FROM ( SELECT MAX(price) FROM `table` tbl WHERE p.person_id = 1 GROUP BY item_id ) AS x

MySQL: check that a set of queries returns the same row count : : but I don't know what the count is

We read values from a set of sensors, occasionally a reading or two is lost for a particular sensor , so now and again I run a query to see if all sensors have the same record count.
GROUP BY sensor_id HAVING COUNT(*) != xxx;
So I run a query once to visually get a value of xxx and then run it again to see if any vary.
But is there any clever way of doing this automatically in a single query?
You could do:
HAVING COUNT(*) != (SELECT MAX(count) FROM (
SELECT COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t)
Or else group again by the count in each group (and ignore the first result):
SELECT count, GROUP_CONCAT(sensor_id) AS sensors
FROM (
SELECT sensor_id, COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t
GROUP BY count
ORDER BY count DESC
LIMIT 1, 18446744073709551615
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
ORDER BY count
Will show a list of the sensor_id along with a count of all the records it has, you can then manually check to see if any vary.
SELECT * FROM (
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
) AS t1
GROUP BY count
Will show all the counts that vary, but the group by will lose information about which sensor_ids have which counts.
---EDIT---
Taken a bit from both mine and eggyal's answer and created this, for the count that is most frequent I call the id default, and then for any values that stand out I have given them separate rows. This way you maintain the readability of a table if you have many results Multi Row, but also have a simple one row column if all counts are the same One Row. If however you are happy with the concocted strings then go with eggyal's answer.
Might be a bit over the top but here goes:
select 'default' as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)=
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5 group by count
union all
select t5.id as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)<>
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5

Selecting the Max and Min records in one MySQL command

I need to be able to select two records from a table based on ID.
I need the first one, and the last one (so min, and max)
Example:
Customer
ID NAME
1 Bob
50 Bob
Any ideas? Thanks.
SELECT MIN(id), MAX(id) FROM tabla
EDIT: If you need to retrive the values of the row you can do this:
SELECT *
FROM TABLA AS a, (SELECT MIN(id) AS mini,
MAX(id) AS maxi
FROM TABLA) AS m
WHERE m.maxi = a.id
OR m.mini = a.id;
Is this what you are looking for?
select id, name from customers where id = ( select max(id) from customers )
union all
select id, name from customers where id = ( select min(id) from customers )
Now I have tested this type of query on a MySQL database I have access, and it works. My query:
SELECT nome, livello
FROM personaggi
WHERE livello = (
SELECT max( livello )
FROM personaggi )
If ties for first and/or last place are not a concern, then consider the following query:
(SELECT id, name FROM customers ORDER BY id DESC LIMIT 1)
UNION ALL
(SELECT id, name FROM customers ORDER BY id LIMIT 1);
It worked for me:
select * from customer where id in ((select min(id) from customer),(select max(id)
from customer));
SELECT MIN(value), MAX(value) FROM table