Delete all rows except 2 for each SID (descending order) - mysql

I have a table with this structure. For each SID there are different ITEMID
| sid | itemid |
|---| ---------|
| 1 | 20600 |
| 1 | 20598 |
| 1 | 20597 |
| 1 | 20596 |
| 1 | 20595 |
| 1 | 20594 |
...
...
| 2 | 19600 |
| 2 | 19598 |
| 2 | 19597 |
| 2 | 19596 |
| 2 | 19595 |
| 2 | 19594 |
...
...
What I need is to delete all but the last 2 rows with the ITEMIDs sorted in DESCENDING way.
This is the result I want to obtain:
| sid | itemid |
|---| ---------|
| 1 | 20600 |
| 1 | 20598 |
| 2 | 19600 |
| 2 | 19598 |
Thanks
Andrea

DELETE t0
FROM test t0
JOIN ( SELECT t1.sid,
( SELECT itemid
FROM test t2
WHERE t1.sid = t2.sid
ORDER BY itemid DESC LIMIT 1,1 ) itemid
FROM ( SELECT DISTINCT t3.sid
FROM test t3 ) t1 ) t4 USING (sid)
WHERE t0.itemid < t4.itemid;
https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=c6d67da817ddbb9fb890693564bcd49c

On MySQL 8+, we can try a delete join using ROW_NUMBER:
DELETE t1
FROM yourTable t1
INNER JOIN
(
SELECT sid, itemid,
ROW_NUMBER() OVER (PARTITION BY sid ORDER BY itemid DESC) rn
FROM yourTable
) t2
ON t2.sid = t1.sid AND t2.itemid = t1.itemid
WHERE
t2.rn > 2;

Related

MySQL find duplicates based on another column value

I have the following table
+----+------+-------+
| id | user | value |
+----+------+-------+
| 1 | 10 | A |
| 2 | 12 | B |
| 3 | 24 | A |
| 4 | 33 | C |
+----+------+-------+
I want to retreive all the duplicates users that have the same key
+----+------+-------+
| id | user | value |
+----+------+-------+
| 1 | 10 | A |
| 3 | 24 | A |
+----+------+-------+
I've tried that with no luck
SELECT DISTINCT A.user, A.value
FROM table as A
INNER JOIN ( SELECT value FROM table GROUP BY value HAVING COUNT(value) > 1 ) AS B
ON A.value = B.value
You may try below query -
SELECT id, user, value
FROM YUOR_TABLE T1
WHERE EXISTS (SELECT 1
FROM YOUR_TABLE T2
WHERE T1.value = T2.value
AND T1.user <> T2.user)

SQL query to get minimal sum value and associated column from table

I have following tables:
t1 - Items
| Id | Item |
| 1 | I1 |
| 2 | I2 |
t2 - Item_elements
| Id | Item_id | Element | Our_quantity | Client_quantity |
| 1 | 1 | E11 | 100 | 0 |
| 2 | 1 | E12 | 20 | 300 |
| 3 | 2 | E21 | 300 | 100 |
| 4 | 2 | E22 | 5 | 300 |
t3 - Element_operations
| Id | Element_id | Operations_number |
| 1 | 1 | 100 |
| 2 | 1 | 50 |
| 3 | 2 | 50 |
| 4 | 2 | 50 |
| 5 | 3 | 50 |
| 6 | 3 | 50 |
| 7 | 3 | 50 |
| 8 | 3 | 50 |
| 9 | 4 | 10 |
I need SQL query which return table witch items (t1) AND element row associated with item table which has minimum operations number
Desired Output:
Table should look like
| Id|Item| Id_el |Our_quantity| Client_quantity | Count Operations_number|
| 1| I1 | 2 | 20 | 300 | 100 |
| 2| I2 | 4 | 5 | 300 | 10 |
result
I tried that query
SELECT t2.Id,Item_id,Our_Quantity,Client_Quantity,SUM(Operations_number)
FROM t2 LEFT JOIN t3 ON t2.Id=t3.Id_el GROUP BY t2.Id)
Tried Result:
| Id | Item_id | Our_quantity | Client_quantity |SUM(Operations_number)
| 1 | 1 | 100 | 0 | 150
| 2 | 1 | 20 | 300 | 100
| 3 | 2 | 300 | 100 | 200
| 4 | 2 | 5 | 300 | 10
What should I do next?
Now I have 2 table:
| Element Id | Item_id |Sum operations_number for element |
| 1 | 1 | 150 |
| 2 | 1 | 100 |
| 3 | 2 | 200 |
| 4 | 2 | 10 |
| Item Id | Item |
| 1 | I1 |
| 2 | I2 |
How can I join them to get this table?
Item Element who has minimal sum operations number.
| Item Id | Item | Element_Id | Sum operations_number for element |
| 1 | I1 | 2 | 100 |
| 2 | I2 | 4 | 10 |
You could get desired output using this..
SELECT
t.*,
MIN(t.opsum) AS `Count Operations_number`
FROM
(SELECT
a.*,
b.Id AS `Id_el`,
b.`Our_quantity`,
b.`Client_quantity`,
SUM(c.`Operations_number`) AS opsum
FROM
`t1` AS a
LEFT JOIN `t2` AS b
ON a.`Id` = b.`Item_id`
LEFT JOIN `t3` AS c
ON b.`Id` = c.`Element_id`
GROUP BY a.Id,
b.Id
ORDER BY a.`Id` ASC,
opsum ASC) AS t
GROUP BY t.Id ;
FIDDLE HERE
Maybe if you use the MIN() method in the desired column, as example:
SQL
SELECT t2.Id,Item_id, MIN(Our_Quantity), Client_Quantity, SUM(Operations_number)
FROM t2 LEFT JOIN t3
ON t2.Id=t3.Id_el
GROUP BY t2.Id
You may try this..
For mysql 8+
with cte as (
SELECT t1.id as Item_id, t1.item, t2.id as Ele_Id, t2.Element , t2.Our_quantity , t2.Client_quantity , t3.Operations_number
from Items as t1
inner join Item_elements as t2 on t1.id=t2.Item_id
inner join Item_elements as t3 on t2.id = t3.Element_id
)
, ct as (
select row_number() over ( partition by t1.id order by t2.Our_quantity ) as Slno, * from cte
)
select c.item_id, c.item, c.Ele_id, c.Element, c.our_quantity, c.client_quantity, t.Count_Operations_number
from ct as c
inner join
(
select distinct Element_id , sum(Operation_number) as Count_Operations_number
from Element_operations group by Element_id
) as t
on c.Ele_id=t.Element_id
where c.slno=1
Try the below query, hope this is what you are asking
select t1.Id as 'Id',t1.Item as 'Item',
t.Id as 'Id_el', t.Our_quantity as 'Our_quantity',t.Client_quantity as 'Client_quantity',
sum(t3.Operations_number) as 'Count Operations_number'
from t1 join (select *
from t2 where (Item_id,Our_quantity) in
( select Item_id, min(Our_quantity) from t2 group by Item_id)) t on t1.Id=t.Item_id
join t3 on t.Id=t3.Element_id
group by t1.Id;
Do you want it in the minimum order of SUM(Operations_number)?
Try this
I have updated the answer so this will get the first table also.
SELECT t1.id,
t1.item,
id_el,
our_quantity,
client_quantity,
sum
FROM t1
JOIN (SELECT t2.id AS Id_el,
t2.item_id,
t2.our_quantity AS our_quantity,
t2.client_quantity AS client_quantity,
sum
FROM t2
JOIN (SELECT t3.element_id,
Sum(operations_number) AS sum
FROM t3
GROUP BY element_id) AS b
ON t2.id = b.element_id) AS c
ON t1.id = c.item_id
ORDER BY sum ASC
Output would be:

sort data by specific order sequence (mysql)

So, let say I have this data
id | value | group
1 | 100 | A
2 | 120 | A
3 | 150 | B
4 | 170 | B
I want to sort it so it become like this
id | value | group
1 | 100 | A
3 | 150 | B
2 | 120 | A
4 | 170 | B
there will be more group than that, so if I the data ordered the group like (A,C,B,D,B,C,A), it will become (A,B,C,D,A,B,C)
You can add a counter column to the table, which will be used to sort the table:
select t.id, t.value, t.`group`
from (
select t.id, t.value, t.`group`,
(select count(*) from tablename
where `group` = t.`group` and id < t.id) counter
from tablename t
) t
order by t.counter, t.`group`
See the demo.
Results:
| id | value | group |
| --- | ----- | ----- |
| 1 | 100 | A |
| 3 | 150 | B |
| 2 | 120 | A |
| 4 | 170 | B |
You can approach this as
SELECT *
FROM `tablename`
ORDER BY
row_number() OVER (PARTITION BY `group` ORDER BY `group`), `group`

MySQL | Select two max. values from one table

I have ID (TV-Series ID), T (Translator ID), S (Season), E (Episode)
I need to convert this:
| ID | T | S | E |
| 1 | 1 | 1 | 2 |
| 1 | 1 | 1 | 3 |
| 1 | 2 | 1 | 3 |
| 2 | 3 | 2 | 1 |
| 2 | 3 | 3 | 1 |
Into this:
| ID | T | S | E |
| 1 | 1 | 1 | 3 |
| 1 | 2 | 1 | 3 |
| 2 | 3 | 3 | 1 |
My idea:
SELECT `ID, `T`, `S`, `E`
FROM `UPDATE`
WHERE
`S` = (SELECT MAX(`S`) FROM `UPDATE` WHERE `ID` = `ID`)
AND `E` = (SELECT MAX(`E`) FROM `UPDATE` WHERE `ID` = `ID` AND `S` = (SELECT MAX(`S`) FROM `UPDATE` WHERE `ID` = `ID`))
GROUP BY `ID`, `T`
ORDER BY `TIMESTAMP` DESC
I think this would work. You need to first identify the max S for each ID and T. Once you've identified those, you can join back to the original table on all three fields to get the max E.
SELECT A.ID, A.T, A.S, MAX(B.E) as E
FROM (
SELECT ID, T, MAX(S) AS S
FROM `UPDATE` U
GROUP BY ID, T) A
INNER JOIN `UPDATE` B
ON A.ID = B.ID AND A.T = B.T AND A.S = B.S
GROUP BY A.ID, A.T, A.S
using not exists() to get the latest season for each pair of id,t and max() to get the latest episode.
select id, t, s, max(e) as e
from tbl
where not exists (
select 1
from tbl as i
where i.id = tbl.id
and i.t = tbl.t
and i.s > tbl.s
)
group by id, t, s
or using a left join as:
select tbl.id, tbl.t, tbl.s, max(tbl.e) as e
from tbl
left join tbl i
on i.id = tbl.id
and i.t = tbl.t
and i.s > tbl.s
where i.id is null
group by tbl.id, tbl.t, tbl.s;
rextester demo: http://rextester.com/LAFPS18322
returns
+----+---+---+---+
| id | t | s | e |
+----+---+---+---+
| 1 | 1 | 1 | 3 |
| 1 | 2 | 1 | 3 |
| 2 | 3 | 3 | 1 |
+----+---+---+---+

MySQL SELECT value before MAX

How to select 1st, 2nd or 3rd value before MAX ?
usually we do it with order by and limit
SELECT * FROM table1
ORDER BY field1 DESC
LIMIT 2,1
but with my current query I don't know how to make it...
Sample table
+----+------+------+-------+
| id | name | type | count |
+----+------+------+-------+
| 1 | a | 1 | 2 |
| 2 | ab | 1 | 3 |
| 3 | abc | 1 | 1 |
| 4 | b | 2 | 7 |
| 5 | ba | 2 | 1 |
| 6 | cab | 3 | 9 |
+----+------+------+-------+
I'm taking name for each type with max count with this query
SELECT
`table1b`.`name`
FROM
(SELECT
`table1a`.`type`, MAX(`table1a`.`count`) AS `Count`
FROM
`table1` AS `table1a`
GROUP BY `table1a`.`type`) AS `table1a`
INNER JOIN
`table1` AS `table1b` ON (`table1b`.`type` = `table1a`.`type` AND `table1b`.`count` = `table1a`.`Count`)
and I want one more column additional to name with value before max(count)
so result should be
+------+------------+
| name | before_max |
+------+------------+
| ab | 2 |
| b | 1 |
| cab | NULL |
+------+------------+
Please ask if something isn't clear ;)
AS per your given table(test) structure, the query has to be as follows :
select max_name.name,before_max.count
from
(SELECT type,max(count) as max
FROM `test`
group by type) as type_max
join
(select type,name,count
from test
) as max_name on (type_max.type = max_name.type and count = type_max.max )
left join
(select type,count
from test as t1
where count != (select max(count) from test as t2 where t1.type = t2.type)
group by type
order by count desc) as before_max on(type_max.type = before_max .type)