Delete all rows from a MYSQL table except TOP/BOTTOM 50 rows - mysql

http://sqlfiddle.com/#!2/d21f3/1
I have a table with some entries here, I want to keep only 50 messages in this table sorted by message_id, and DELETE the rest of entries.
Please help me with the query.
Thanks in advance.

E.g..
DELETE a
FROM chat_history a
LEFT
JOIN
( SELECT x.message_id
FROM chat_history x
JOIN chat_history y
ON y.message_id >= x.message_id
GROUP
BY x.message_id
HAVING COUNT(*) <= 50
) b
ON b.message_id = a.message_id
WHERE b.message_id IS NULL;
http://sqlfiddle.com/#!2/361b4/1

Try this one i have used ORDER BY message_id DESC change it as you want it will delete all except the seleted 50 entries, i have aliased the query because you cannot use same table to select with delete operation
DELETE FROM `chat_history` WHERE id NOT IN ( SELECT t.id FROM
(SELECT id FROM chat_history ORDER BY message_id DESC LIMIT 50 ) t)

Related

What's wrong with this MYSQL DELETE statement?

I want to delete records from a table greater than a certain message_id.
MY delete statement doesn't seem to working.
http://sqlfiddle.com/#!2/4f8ee/1
Thanks in advance
DELETE c
FROM `chat_history3` c
inner join
(
select message_id from `chat_history3`
where clan_id=4
ORDER BY message_id DESC
limit 30, 30000
) x
on c.`message_id` < x.`message_id`
SQLFiddle demo

mysql delete rows keeping the last 5 for the each user_id

I have a mysql table ("c5_imgs") with the columns "user_id" (varchar) and "date" (timestamp). The amount of data in this particular table grew much more than I was initially expecting, and now I'm trying to delete all of the records for each user_id except the most recent 5.
I can get the rows I want to delete, for a given user_id:
select *
FROM c5_imgs i
where
date < (
select date
from c5_imgs i2
where i.user_id = i2.user_id
order by i2.date desc
limit 4,1
)
and user_id = 'xxx'
but I'm having problems deleting these rows:
delete
FROM c5_imgs
where
date < (
select date
from c5_imgs i2
where 'xxx' = i2.user_id
order by i2.date desc
limit 4,1
)
and user_id = 'xxx'
#1093 - You can't specify target table 'c5_imgs' for update in FROM clause
and i want to make a generic query for all the user_id, not just for one at a time... any help would be appreciated, thanks.
Edit: chetan's answer helped me with the deletion for one of the user_id's but I'm looking for a more generic solution for all the user_id's.
Edit2: the query i ended up using was based on Christian's answer:
delete aa.*
from c5_imgs aa,
(
select distinct c.user_id as user_id,
(select x.date
from c5_imgs as x
where x.user_id = c.user_id
order by x.date desc
limit 4,1) as date
from c5_imgs as c
) bb
where aa.user_id = bb.user_id and aa.date < bb.date
You can do it in three steps:
First
create table aux
select distinct c.user_id as user_id,
(select x.date
from c5_imgs as x
where x.user_id = c.user_id
order by x.date desc
limit 4,1) as date
from c5_imgs as c;
Second
delete c5_imgs
from c5_imgs as c
inner join aux as a on a.user_id = c.user_id
where c.date < a.date;
Third
drop table aux;
If working with large tables, you could create indexes on the columns of aux table to speed up the delete action.
CREATE INDEX aux_idx1 ON aux(user_id);
CREATE INDEX aux_idx2 ON aux(date);
Note that you could simplify and improve speed of first step if you have a users table from which you can get the distinct user ids.
This does not guarantee keeping exactly 5 most recent images. In cases where the date is the exact same for more than one image in the 5th and next positions, this will not work as required.
You can do that using join. for example
delete a.*
FROM c5_imgs a, (
select date
from c5_imgs
where 'xxx' = user_id
order by date desc
limit 4,1
) b
where
a.date < b.date
and a.user_id = 'xxx';
I haven't run this query, but it should work. Work around if necessary.

MySql query ordering

Here is my data. I want to take 6 rows, but I want all HeadlineCategoryId's to be unique in my result list. If I select the top 6 I would take 2 rows from HeadlineCategoryID 20 (6,2). Do you have any suggestions about it?
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT HeadlineCategoryID, MAX(Creation) max_date
FROM TableName
GROUP BY HeadlineCategoryID
) b ON a.HeadlineCategoryID = b.HeadlineCategoryID AND
a.Creation = b.max_date
ORDER BY a.Creation DESC -- << specify here how are you going to sort
LIMIT 6 -- the records you want to get
UPDATE 1
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT HeadlineCategoryID, MAX(NewsID) max_id
FROM TableName
GROUP BY HeadlineCategoryID
) b ON a.HeadlineCategoryID = b.HeadlineCategoryID AND
a.NewsID = b.max_id
ORDER BY a.Creation DESC -- << specify here how are you going to sort
LIMIT 6 -- the records you want to get
It looks like you want the six most recent records, but unique by HeadlineCategoryId. If so, this will work:
select top 6 NewsId, Creation, HeadlineCategoryId
from (select t.*,
row_number() over (partition by HeadlineCategoryId order by Creation desc) as seqnum
from t
) t
where seqnum = 1
As a note . . . This question originally indicated that it was using SQL Server, not MySQL. The solution in MySQL is not as simple. Here is one method with not exists:
select NewsId, Creation, HeadlineCategoryId
from t
where not exists (select 1
from t t2
where t2.HeadlineCategoryId = t.HeadlineCategoryId and
t2.id < t.id)
limit 6
The not exists portion is saying "where there is no other record with a larger id for a given headline category".

mysql delete earlier datas if max(id) - min(id) > 50,000

I have a table in which I need to keep the total number of rows within 50,000. This table includes an Id field (id is auto incremental).
How can I check if max(id) - min(id) > 50,000, then delete the earlier rows?
DELETE FROM news WHERE if (max(id) - min(id) > 50000)
This query will delete all the rows if max(id) - min(id) > 50000, what is the correct way? Ideally I need a one line command, excuse in SSH method. thanks.
DELETE d
FROM news AS d
JOIN
( SELECT MAX(id)-50000 AS lim
FROM news
) AS m
ON d.id < m.lim ;
The above will not leave exactly 50K rows of course, as there may be gaps in the id sequence. But I guess this is expected and not a problem. If you really want to leave exactly 50K rows, any statement will probably be less efficient. You can try this one:
DELETE d
FROM news AS d
JOIN
( SELECT id AS lim
FROM news
ORDER BY id DESC
LIMIT 1 OFFSET 50000
) AS m
ON d.id <= m.lim ;
Delete from news where id < max(id)-50000
DELETE FROM news
WHERE id NOT IN (SELECT id FROM news ORDER BY id DESC LIMIT 50000)

Selecting rows with unique field values in mysql

I have these columns for table comments:
id
content
add_date
uid
school_id
Rows can have the same school_id.
I want to select the latest data according to add_date, but only 1 row per school_id (no duplicate for school_id) with limit of 10.
I've tried many codes already and its not working for me.
Any help would be appreciated.
This is what we call Greatest N per Group. You can achieved this by putting into a subquery so it can be joined against the non-grouped table (comments).
Try this:
SELECT c.*
FROM
(
SELECT school_id, MAX(add_date) maxDate
FROM comments
GROUP BY school_id
) x INNER JOIN comments c
ON x.school_id = c.school_ID AND
x.maxDate = c.add_date
ORDER BY x.maxDate desc
LIMIT 10
select C.ID, C.Content, t1.MaxDate as [add_date], C.uid, t1.school_id
from (selet school_id, max(add_Date) as 'MaxDate'
from comments
group by school_id) T1
inner join comments C on T1.school_id = C.school_id and C.add_Date= T1.MaxDate
LIMIT 10
If you want to choose which 10 rows return, add an order by, or a Where clause
select c1.*
from comments c1
where add_date = (select max(add_date) from comments c2 where c2.school_id =c1.school_id)
order by add_date desc
limit 10
create indexes on comments(add_date) and comments(school_id, add_date)