Sql Query to retain max 2 duplicate records - mysql

I have the following data:
Name ID Date
Dave | 123 | 1-2-2011
Jim | 123 | 1-3-2011
Mike | 123 | 1-10-2011
Bill | 111 | 1-2-2011
Henry | 222 | 1-3-2011
Larry | 222 | 1-4-2011
I need a delete query to reduce this to:
Jim | 123 | 1-3-2011
Mike | 123 | 1-10-2011
Bill | 111 | 1-2-2011
Larry | 222 | 1-4-2011
i.e. I want to keep the two latest records for each ID.
I tried this:
Delete FROM UserTable a
WHERE
Date <> (SELECT MAX(Date) FROM UserTable b WHERE a.ID = b.ID)
AND ID IN (SELECT ID FROM UserTable GROUP BY ID HAVING COUNT(*) > 1)
but this retains only the latest 1 unique records.

Try something of the sort:
SELECT col1, col2, col3, COUNT(*)
FROM (SELECT DISTINCT * FROM your_TableName) AS T1
GROUP BY col2, col3

try using this code below depending on what you want to request try using ASC or DESC
SELECT column_name,column_name
FROM table_name
ORDER BY column_name,column_name ASC|DESC;
Try also reading up on your sql http://www.w3schools.com/sql/sql_orderby.asp

Partition over can be used to retain more than one duplicate.
delete from UserTable
where (id, date) in (
select id,date from (
select id,date,
row_number() over (partition by id order by date desc) as temp
from UserTable)
where temp > 2
);
This query adds another column with row number partitioned by the id, ordered by date and then deletes those records which have row number greater than 2.

Related

Get last 3 rows from SQL table without duplicates of a row

Lets say we have a table that looks like this:
+---------------+----------------+-------------------+
| ID | random_string | time |
+---------------+----------------+-------------------+
| 2 | K2K3KD9AJ |2022-07-21 20:41:15|
| 1 | SJQJ8JD0W |2022-07-17 23:46:13|
| 1 | JSDOAJD8 |2022-07-11 02:52:21|
| 3 | KPWJOFPSS |2022-07-11 02:51:57|
| 1 | DA8HWD8HHD |2022-07-11 02:51:49|
------------------------------------------------------
I want to select the last 3 entries into the table, however they must all have separate ID's.
Expected Result:
+---------------+----------------+-------------------+
| ID | random_string | time |
+---------------+----------------+-------------------+
| 2 | K2K3KD9AJ |2022-07-21 20:41:15|
| 1 | SJQJ8JD0W |2022-07-17 23:46:13|
| 3 | KPWJOFPSS |2022-07-11 02:51:57|
------------------------------------------------------
I have already tried:
SELECT DISTINCT id FROM table ORDER BY time DESC LIMIT 3;
And:
SELECT MIN(id) as id FROM table GROUP BY time DESC LIMIT 3;
If you're not on MySQL 8, then I have two suggestions.
Using EXISTS:
SELECT m1.ID,
m1.random_string,
m1.time
FROM mytable m1
WHERE EXISTS
(SELECT ID
FROM mytable AS m2
GROUP BY ID
HAVING m1.ID=m2.ID
AND m1.time= MAX(time)
)
Using JOIN:
SELECT m1.ID,
m1.random_string,
m1.time
FROM mytable m1
JOIN
(SELECT ID, MAX(time) AS mxtime
FROM mytable
GROUP BY ID) AS m2
ON m1.ID=m2.ID
AND m1.time=m2.mxtime
I've not test in large data so don't know which will perform better (speed) however this should return the same result:
Here's a fiddle
Of course, this is considering that there will be no duplicate of exact same ID and time value; which seems to be very unlikely but still it's possible.
Using MySql 8 an easy solution is to assign a row number using a window:
select Id, random_string, time
from (
select *, Row_Number() over(partition by id order by time desc) rn
from t
)t
where rn = 1
order by time desc
limit 3;
See Demo

In MySQL, SELECT and COUNT from two différente tables

I have two tables in MySQL:
___Table1
| id | name |
|----|------|
| 98 | Fred |
___Table2
| link | amount |
|------|--------|
| 98 | 100.00 |
| 98 | 50.00 |
How can I SELECT all the items from ___Table1 and SUM datas from the ___Table2.
The desired output should be:
Fred = 150.00
This is what I have tried so far:
SELECT
SELECT SUM(amount) AS amount FROM ___Table2 WHERE ___Table2.link = ___Table1.id,
(SELECT * FROM ___Estimates ORDER BY EST_Id DESC)
Thanks.
SELECT
t1.id AS id,
t1.name as name,
IFNULL ( SUM( t2.amount ), 0 ) AS account
FROM
___Table2 t2
RIGHT JOIN ___Table1 t1 ON t2.link = t1.id
GROUP BY
t2.link
You could group by name instead but you didn't say if it was unique. If you just need a single user then add a where clause to select that user:
select name, sum(amount) as 'sum'
from ___Table1
join ___Table2 on ___Table1.id = ___Table2.link
group by ___Table1.id
Those table names are awful (you can't tell how many underscores by just looking at it), also it's a good idea to use the same name for the primary and foreign key (_id is the often used standard).

sql group by with excluded data

My table:
id | request | subject | date
1 | 5 | 1 | 576677
2 | 2 | 3 | 576698
3 | 5 | 1 | 576999
4 | 2 | 3 | 586999
5 | 2 | 7 | 596999
Need to select unique records by two columns(request,subject). But if we have different pairs of request-subject(2-3, 2-7), this records should be excluded from resulted query.
My query now is:
SELECT MAX(id), id, request, subject, date
FROM `tbl`
GROUP BY request, subject
having count(request) > 1
order by MAX(id) desc
How to exclude record with id=4, id=5 from this query? Thanks!
You may group by request, and then check for every group if all subjects in it are equal. You could do it using MIN() and MAX():
SELECT request, MIN(subject) AS subject
FROM table_1
GROUP BY request
HAVING MIN(subject) = MAX(subject)
As for your update, I assume you want all the fields for the max ID in the group (in your example, ID 3). The query would then look like this one:
SELECT *
FROM table_1 t
WHERE t.id IN (SELECT MAX(s.id)
FROM table_1 s
GROUP BY s.request
HAVING MIN(s.subject) = MAX(s.subject))
ORDER BY t.id
You can try this.
select * from MyTable T1
WHERE NOT EXISTS( SELECT * FROM MyTable T2
WHERE T1.id <> T2.id
and T1.request = T2.request
and T1.subject <> T2.subject)
Sql Fiddle

Selecting non-group field from query with aggregate function

I have a table tbl with three columns:
id | fk | dateof
1 | 1 | 2012-01-01
2 | 1 | 2012-01-02
3 | 2 | 2012-02-01
4 | 2 | 2012-03-01
5 | 3 | 2012-04-01
id is the ID of the row, fk is a foreign key to another table and dateof is a date column.
What I want is to get the id where the dateof is the latest grouped by fk. What I've tried:
SELECT id, MAX(dateof) FROM tbl GROUP BY fk
But I get results like this:
1 | 2012-01-02
3 | 2012-03-01
5 | 2012-04-01
When I want:
2 | 2012-01-02
4 | 2012-03-01
5 | 2012-04-01
How can I query and get the results I'm looking for? MySQL server if it matters. Thanks.
Personally I would do
SELECT id, tbl.dateof dateof
FROM tbl
INNER JOIN
(SELECT fk, MAX(dateof) dateof
FROM tbl
GROUP BY fk) temp
ON tbl.fk = temp.fk AND tbl.dateof = temp.dateof
Gordon's answer is correct and less code, but I prefer creating a temp table. It's more clear to other developers what I'm doing.
To get what you want:
select t.*
from (select tbl.*,
row_number() over (partition by fk order by dateof desc) as seqnum
from tbl
) t
where seqnum = 1
This assumes that you are using a reasonable database that has window functions. You don't specify the database in your question.

MySQL: How to GROUP BY a field to retrieve the rows with ORDER BY another field?

assume following data:
Data:
id | date | name | grade
--------+---------------+-----------+---------------
1 | 2010/12/03 | Mike | 12
2 | 2010/12/04 | Jenny | 12
3 | 2010/12/04 | Ronald | 15
4 | 2010/12/03 | Yeni | 11
i want to know who has the best grade in each day, something like this:
Desired Result:
id | date | name | grade
--------+---------------+-----------+---------------
1 | 2010/12/03 | Mike | 12
3 | 2010/12/04 | Ronald | 15
i thought query should look like this:
SELECT name FROM mytable
GROUP BY date
ORDER BY grade DESC
but it returns something like this:
Current Unwanted Result:
id | date | name | grade
--------+---------------+-----------+---------------
1 | 2010/12/03 | Mike | 12
2 | 2010/12/04 | Jenny | 12
i searched and i found the reason:
GROUP BY happens before ORDER BY so it does not see and can't apply ORDER.
so how can i apply ORDER on GROUP BY?
Note: please keep in mind that i need the most simple query, because my query is actually very complex, i know i can achieve this result by some subquery or JOINing, but i want to know how to apply ORDER to GROUP BY. thanks
I used Oracle for this example, but the SQL should work in mysql (you may need to tweak the to_date stuff to work with mysql). You really need a subquery here to do what you are asking.
CREATE TABLE mytable (ID NUMBER, dt DATE, NAME VARCHAR2(25), grade NUMBER);
INSERT INTO mytable VALUES(1,to_date('2010-12-03','YYYY-MM-DD'),'Mike',12);
INSERT INTO mytable VALUES(1,to_date('2010-12-04','YYYY-MM-DD'),'Jenny',12);
INSERT INTO mytable VALUES(1,to_date('2010-12-04','YYYY-MM-DD'),'Ronald',15);
INSERT INTO mytable VALUES(1,to_date('2010-12-03','YYYY-MM-DD'),'Yeni',11);
SELECT id
, dt
, name
, grade
FROM mytable t1
WHERE grade = (SELECT max(grade)
FROM mytable t2
WHERE t1.dt = t2.dt)
ORDER BY dt
Results:
ID DT NAME GRADE
1 12/3/2010 Mike 12
2 12/4/2010 Ronald 15
I know you said you wanted a GROUP / ORDER only solution but you will need to use a subquery in this instance. The simplest way would be something like this:
SELECT id, date, name, grade
FROM mytable t1
WHERE grade =
(SELECT MAX(t2.grade) FROM mytable t2 WHERE t1.id = t2.id)
This would show multiple students if they shared the highest grade for the day.