How to get previous last row in MySQL - mysql

I have below mentioned two tables.
Table1
ID ref_id
O-1 rt-1-r
O-2 rx-2-e
Table2
ref_id seq value
rt-1-r 1 10
rt-1-r 2 15
rt-1-r 3 0
rt-1-r 4 18
rx-2-e 12 1
rx-2-e 13 13
rx-2-e 14 21
Required Output
ID Value
O-1 0
O-2 13
I have tried below mentioned query but it is working for one ID when I pass multiple ID in IN it is not working.
select b.ID, a.Value
FROM Table2 a
LEFT JOIN Table1 b ON a.ref_id = b.ref_id
WHERE a.ID IN ('O-1')
order by a.seq desc limit 1 OFFSET 1;

I would use ROW_NUMBER here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY ref_id ORDER BY seq DESC) rn
FROM Table2
)
SELECT t1.ID, t2.value
FROM Table1 t1
INNER JOIN cte t2
ON t2.ref_id = t1.ref_id
WHERE t2.rn = 2;
I don't like not using analytic functions for this, but if you had to here is one way:
SELECT
t1.ID,
(SELECT value FROM Table2 t2
WHERE t2.ref_id = t1.ref_id AND
t2.seq < (SELECT MAX(s.seq) FROM Table2 s WHERE s.ref_id = t2.ref_id)
ORDER BY t2.seq DESC LIMIT 1) AS value
FROM Table1 t1;

Related

SQL add same contents

How can I delete all columns that are duplicate and don't have the biggest "amount". I have the following table:
ID TIME AMOUNT
-----------------------------------
1 x 5
2 y 1
2 y 3
3 z 1
3 z 2
3 z 3
But I want it to be like this, so that only the column which has the biggest number "survives":
ID TIME AMOUNT
------------------------------------
1 x 5
2 y 3
3 z 3
How can I do this?
You can get the max amount per id and time and then get the rows matching:
select t.Id, t.Time, t.amount
from myTable t
inner join
(select Id, time, max(amount) as amt
from myTable
group by Id, Time) tmp on t.id = tmp.id and
t.time = tmp.time and
t.amount = tmp.amt
DbFiddle demo
EDIT: You may want to add DISTINCT depending on your needs.
One other approach using a CTE
with del as (
select *,
First_Value(amount) over(partition by id order by amount desc) maxamount
from t
)
delete from t
using t join del on t.id = del.id and t.amount < maxamount;
WITH cte AS
(
SELECT
ID,
ROW_NUMBER() OVER (PARTITION BY TIME ORDER BY AMOUNT DESC) AS ROWNUM
FROM
MyTable
)
DELETE MyTable
FROM MyTable
JOIN cte USING (ID)
WHERE ROWNUM > 1;
WITH syntax requires MySQL 8.0.
I think some of the answers here are overly complicated.
delete t
from yourtable t
join yourtable t2 on t.id = t2.id
and t.time = t2.time
and t2.amount > t.amount

How to write a simple self join query to find result by comparing it self?

Let me being honest, I am Java developer assigned with this SQL development work where I need to list out all the orderId which having nodeName 'Delay' and id is 'MAX(id)'
id
orderId
nodeName
1
2
Rain
2
2
Summer
3
2
Delay
4
2
Winter
5
5
Rain
6
5
Delay
7
5
Summer
8
5
Winter
9
3
Rain
10
3
Summer
11
3
Delay
12
1
Rain
13
1
Delay
14
1
Summer
15
1
Delay
In above example it should fetch orderId 3 and 1 and ignore rest of the all orderId.
I know few might think it's a silly question but I have not much experience on SQL queries so I raised it on this forum.
Use a correlated subquery to check if the last id of each orderId has nodeName = 'Delay':
SELECT DISTINCT t1.orderId
FROM tablename t1
WHERE t1.nodeName = 'Delay'
AND t1.id = (SELECT MAX(t2.id) FROM tablename t2 WHERE t2.orderId = t1.orderId)
Or:
SELECT DISTINCT t1.orderId
FROM tablename t1
WHERE 'Delay' = (
SELECT t2.nodeName
FROM tablename t2
WHERE t2.orderId = t1.orderId
ORDER BY id DESC LIMIT 1
)
Or, with ROW_NUMBER() window function:
SELECT orderId
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY orderId ORDER BY id DESC) rn
FROM tablename
) t
WHERE rn = 1 AND nodeName = 'Delay'
See the demo.
I need to list out all the orderId which having nodeName 'Delay' and id is 'MAX(id)'
One approach is aggregation with a having clause:
select orderid
from t
group by orderid
having max(id) = max(case when nodename = 'Delay' then id end);
Or, if you do use a correlated subquery, not exists comes to mind:
select orderid
from t
where t.nodename = 'Delay' and
not exists (select 1
from t t2
where t2.orderid = t.orderid and
t2.nodename <> 'Delay' and
t2.id > t.id
);
Assuming you are searching for only one row,
try:
SELECT MAX(id), orderId, nodeName
FROM table_name
WHERE nodeName = 'Delay';
If you are not searching for only one row, but for the results with the highest id,
Try:
SELECT *
FROM table_name
WHERE nodeName = 'Delay'
ORDER BY id DESC
LIMIT 5;
you can use following query
select t1.orderId
from tablename t1
join (SELECT MAX(id) as id FROM tablename group by orderId) t2 on t1.id = t2.id
where t1.nodeName = 'Delay'

Select all orders except the max order for each distinct customer

Sorry for the poor formatting but as part of a larger problem, I have created a query that produces this table:
id id2
4 7
4 6
1 3
1 2
1 1
How would I extract the rows that don't have the highest id2 for each id1.
What I want:
id id2
4 6
1 2
1 1
I can only seem to figure out how to get rid of the max id2 overall but not for each distinct id1. Any help on actually differentiating the max id2 for each id1 would be appreciated.
You can try below way -
select a.id, a.id2
from tablename a
where a.id2 <> (select max(a1.id2) from tablename a1 where a.id=a1.id)
If you are using MySQL 8+, then RANK() provides one option:
WITH cte AS (
SELECT id, id2, RANK() OVER (PARTITION BY id ORDER BY id2 DESC) rnk
FROM yourTable
)
SELECT id, id2
FROM cte
WHERE rnk > 1
ORDER BY id DESC, id2 DESC;
Demo
instead of a correlated subquery in the where, you can LEFT JOIN and apply not in...
select id, id2
from yourTable YT
LEFT JOIN
( select id, max( id2 ) highestID2
from YourTable
group by id ) TopPerID
on YT.ID = TopPerID.ID
AND YT.ID2 != TopPerID.highestID2
where TopPerID.id IS NULL
Since you can have id values with only one id2 value, you need to check for that situation as well, which you can do by comparing the MAX(id2) value with the MIN(id2) value in a JOIN:
SELECT t1.*
FROM Table1 t1
JOIN (SELECT id, MAX(id2) AS max_id2, MIN(id2) AS min_id2
FROM Table1
GROUP BY id) t2 ON t2.id = t1.id
AND (t1.id2 < t2.max_id2 OR t2.min_id2 = t2.max_id2)
If we add a row 2, 5 to your sample data this correctly gives the result as
id id2
4 6
1 2
1 1
2 5
Demo on SQLFiddle

How can I add subtotal to table in MySQL?

Assume my table looks like the following:
id count sub_total
1 10 NULL
2 15 NULL
3 10 NULL
4 25 NULL
How can I update this table to look like the following?
id count sub_total
1 10 10
2 15 25
3 10 35
4 25 60
I can do this easy enough in the application layer. But I'd like to learn how to do it in MySQL. I've been trying lots of variations using SUM(CASE WHEN... and other groupings to no avail.
If your id field is sequential and growing then a correlated subquery is one way:
select *, (select sum(count) from t where t.id <= t1.id)
from t t1
or as a join:
select t1.id, t1.count, sum(t2.count)
from t t1
join t t2 on t2.id <= t1.id
group by t1.id, t1.count
order by t1.id
To update your table (assuming the column sub_total already exists):
update t
join (
select t1.id, sum(t2.count) st
from t t1
join t t2 on t2.id <= t1.id
group by t1.id
) t3 on t.id = t3.id
set t.sub_total = t3.st;
Sample SQL Fiddle showing the update.

how to find maximum if i have more than one answer

I have a table:
ID CLUSTERID
1 56
1 24
1 24
1 35
2 13
2 24
Now, i want to get the following:
I want to count per id, which cluster id repeats most of the time.
For example, in ID=1, CLUSTERID=24 repeats most of the time
In ID=2 i have 2 CLUSTER IDs that repeats the same.
So in the output i will have:
ID CLUSTERID
1 24
2 13
2 24
The answer that i wrote (and works)
TT is my original table that have 2 columns: ID and CLUSTER ID
SELECT t3.ID,t3.ClusterID,t3.ListingAmount
FROM
(SELECT ID, ClusterID, COUNT() AS ListingAmount
FROM tt
GROUP BY ID, ClusterID) AS t3 LEFT JOIN
(SELECT ID, MAX(ListingAmount) AS amount
FROM
(SELECT ID, ClusterID, COUNT() AS ListingAmount
FROM tt
GROUP BY ID, ClusterID) AS t2
GROUP BY ID) AS BB ON BB.id=t3.id
WHERE BB.amount=t3.ListingAmount
Can't think of a more elegant solution right now (I'm sure there is), but it seems to do the job:
select t1.id,
t1.clusterid,
t1.cnt
from (
select id,
clusterid,
count(*) as cnt
from foo
group by id, clusterid
) t1
join (select id,
max(cnt) as max_count
from (
select id,
clusterid,
count(*) as cnt
from foo
group by id, clusterid
) tm
group by id
) t2 on t1.id = t2.id
and t1.cnt = t2.max_count
order by t1.id, t1.cnt;
SQLFiddle example: http://sqlfiddle.com/#!2/2cacc/3