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 |
+----+---+---+---+
Related
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;
Okay, so here are my tables:
tests:
+----+------------+
| id | name |
+----+------------+
| 1 | test-one |
| 2 | test-two |
| 3 | test-three |
| 4 | test-four |
| 5 | test-five |
| 6 | test-six |
+----+------------+
testGroups:
+----+-------------+
| id | name |
+----+-------------+
| 1 | group-one |
| 2 | group-two |
| 3 | group-three |
| 4 | group-four |
| 5 | group-five |
| 6 | group-six |
| 7 | group-seven |
| 8 | group-eight |
| 9 | group-nine |
| 10 | group-ten |
+----+-------------+
and testGroupAssignments
+----+--------+---------+
| id | testID | groupID |
+----+--------+---------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 2 | 2 |
| 4 | 2 | 3 |
| 5 | 3 | 1 |
| 6 | 3 | 3 |
| 7 | 4 | 1 |
| 8 | 5 | 6 |
| 9 | 5 | 7 |
| 10 | 5 | 4 |
+----+--------+---------+
What I want is to get every test that has group-one assigned to it, given it has no other group assigned to it.
+--------+-----------+
| testID | testName |
+--------+-----------+
| 1 | test-one |
| 4 | test-four |
+--------+-----------+
I know that I should use a LEFT JOIN and I tried to do:
SELECT
t.id `testID`,
t.name `testName`
FROM
tests `t`
INNER JOIN
testGroupAssignments `tga`
ON
t.id = tga.testID
LEFT JOIN
testGroupAssignments `tga2`
ON
t.id = tga.testID AND tga2.groupID != 1
INNER JOIN
testGroups `tg`
ON
tg.id = tga.groupID
WHERE
tga.groupID = 1
AND
tga2.groupID != 1
AND
tga2.groupID IS NULL
You can try the following:
SELECT t.id AS testID, t.name AS testName
FROM tests t
INNER JOIN testGroupAssignments tga ON t.id = tga.testID
INNER JOIN testGroups tg ON tg.id = tga.groupID
WHERE tga.groupID = 1 AND NOT EXISTS (
SELECT 1
FROM testGroupAssignments
WHERE testID = t.id AND groupID <> 1
)
In case you don't want to show column values of the other tables you can use the following simple query:
SELECT *
FROM tests t
WHERE EXISTS (
SELECT 1
FROM testGroupAssignments tga
WHERE tga.testID = t.id AND tga.groupID = 1
) AND NOT EXISTS (
SELECT 1
FROM testGroupAssignments tga
WHERE tga.testID = t.id AND tga.groupID <> 1
)
demo on dbfiddle.uk
You can do aggregation with JOIN :
SELECT ts.id AS testID, ts.name AS testName
FROM tests ts INNER JOIN
testGroupAssignments tg
ON tg.testID = ts.id
GROUP BY ts.id, ts.name
HAVING COUNT(tg.groupID) = 1;
If you have a duplicate groupIDs then use DISTINCT inside COUNT().
use self join to testgroupassigments table try this.
SELECT t.id AS Testgroupassignments_id,
test.`name` AS Test_name,
testg.`name` AS Test_group_name
FROM stackoverflow.testgroupassignments AS t
LEFT JOIN stackoverflow.tests AS test ON test.id = t.testID
LEFT JOIN stackoverflow.testgroups AS testg ON testg.id = t.groupID
WHERE t.id NOT IN (
SELECT ta.id FROM
stackoverflow.testgroupassignments AS ta
LEFT JOIN stackoverflow.testgroupassignments AS taa ON taa.testID = ta.testID
WHERE ta.id <> taa.id )
This is a followup question to the excellent answer:
SQL Select only rows with Max Value on a Column
SQLFiddle http://sqlfiddle.com/#!2/3077f/2
Table "yourtable":
| id | val | ignore | content |
-------------------------------
| 1 | 10 | 0 | A |
| 1 | 20 | 0 | B |
| 1 | 30 | 1 | C |
| 2 | 40 | 0 | D |
| 2 | 50 | 0 | E |
| 2 | 60 | 1 | F |
When looking for max val per id, following sql is used:
select yt1.*
from yourtable yt1
left outer join yourtable yt2
on (yt1.id = yt2.id and yt1.val < yt2.val )
where yt2.id is null;
So the result will be in this case
| id | val | ignore | content |
-------------------------------
| 1 | 30 | 1 | C |
| 2 | 60 | 1 | F |
The Question is how to filter out by column "ignore" when it's =1 so the result will be
| id | val | ignore | content |
-------------------------------
| 1 | 20 | 0 | B |
| 2 | 50 | 0 | E |
You need to put the condition both in the subquery and the outer query:
select yt1.*
from yourtable yt1 left outer join
yourtable yt2
on yt1.id = yt2.id and yt1.val < yt2.val and yt2.ignore <> 1
where yt2.id is null and yt1.ignore <> 1;
You can simply add another condition and yt1.ignore <> 1, as below:
select yt1.*
from yourtable yt1
left outer join yourtable yt2
on (yt1.id = yt2.id and yt1.val < yt2.val )
where yt2.id is null and yt1.ignore <> 1;
I have the following user table (don't ask me why :) )
| id | cid | attr | text | rdate |
---------------------------------------
| 1 | 1 | name | joe | NULL |
| 2 | 1 | date | NULL | 10.05.2014 |
| 3 | 1 | stat | 2 | NULL |
----------------------------------------
| 4 | 2 | name | joe | NULL |
| 5 | 2 | date | NULL | 05.05.2014 |
| 6 | 2 | stat | 1 | NULL |
----------------------------------------
| 7 | 3 | name | joe | NULL |
| 8 | 3 | date | NULL | 03.05.2014 |
| 9 | 3 | stat | 2 | NULL |
As you can see every user's attribute (name, date, stat) is a row in the table.
Attributes with the same cid belong to the same user.
I would like to delete all the entries which refer to a user whose attribute date is before 08.05.2014 AND whose attribute stat is not 2. So after running this query the table will be:
| id | cid | attr | text | rdate |
---------------------------------------
| 1 | 1 | name | joe | NULL |
| 2 | 1 | date | NULL | 10.05.2014 |
| 3 | 1 | stat | 2 | NULL |
----------------------------------------
| 7 | 3 | name | joe | NULL |
| 8 | 3 | date | joe | 03.05.2014 |
| 9 | 3 | stat | 2 | NULL |
Is it possible? Is this a inner join on the same table?
Group by the cid and use the having clause to run group functions to check out your requirements in every single group
delete from your_table
where cid in
(
select * from
(
select cid
from your_table
group by cid
having sum(attr = 'date' and `date` < '2014-05-08') > 0
and sum(attr = 'stat' and `text` = 2) = 0
) tmp_tbl
)
In MySQL you can't delete from the same table you are selecting from. But you can trick MySQL with another subquery like in the example above.
You can do this with delete/join:
delete t
from table t join
(select cid
from table t
group by cid
having max(case when attr = 'date' and date < '2014-05-08') > 0 and
max(case when attr = 'stat' and text <> '2') > 0
) s
on t.cid = s.cid;
I would do a fairly simple JOIN in the delete statement:-
DELETE a
FROM some_table a
INNER JOIN some_table b
ON a.cid = b.cid
INNER JOIN some_table c
ON a.cid = c.cid
WHERE b.attr = 'date' AND b.date < '2014-05-08'
AND c.attr = 'stat' AND c.text != '2'
Join will do :
Delete from mytable where cid in (select cid from
(select t1.cid FROM mytable t1 INNER JOIN mytable t2 ON t1.cid = t2.cid
WHERE t1.attr = 'date' AND t1.rdate < '2014-05-08'
AND t2.attr = 'stat' AND t2.text != 2) as sq)
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)