The problem
I'm using buddypress for Wordpress it has a table for private messages in side which are thread ids for message threads. Currently there's no limit on how many messages can be in a thread.
I want to create a command that deletes all but the most recent 10 messages in a thread. Below is the logic, but I'm not sure the correct syntax to do it?
Any of you mysql geniuses know the answer?
DELETE FROM TABLEA WHERE id = X delete everything with thread ID x
EXCEPT
(SELECT * FROM TABLEA WHERE id = X ORDER BY date_sent DESC LIMIT 10)
Selects most recent 10 I do not wish deleted.
This should working:
DELETE FROM TABLEA WHERE id = X AND id NOT IN (
SELECT TOP 10 id FROM TABLEA ORDER BY date_sent DESC
)
The sub-select of this query get the last 10 sent items. The main query have to delete the item with id X except the item is on the result of the sub-select.
I'm not sure how the table in buddypress works but I guess TABLEA should have its on primary key id. If TABLEA does have its own primary key id, here's my solution.
DELETE FROM TABLEA WHERE id = x AND TABLEA_id NOT IN
(SELECT TABLEA_id FROM TABLEA WHERE id = x ORDER BY date_sent DESC LIMIT 10)
Related
I would like to delete my MySQL selection.
Here is my MySQL selection request:
SELECT *
FROM Items
WHERE id_user=1
ORDER
BY id_user
LIMIT 2,1
With this working request, I select the third item on my table which has as id_user: 1.
Now, I would like to delete the item that has been selected by my request.
I am looking for a same meaning request which would look like this :
DELETE FROM Items (
SELECT * FROM Items WHERE id_user=1 ORDER BY id_user LIMIT 2,1
)
The first thing to note is that there is an issue with your query. You are filtering on a unique value of id_user and sorting on the same column. As all records in the resultset will have the same id_user, the actual order of the resultset is undefined, and we cannot reliably tell which record comes third.
Assuming that you have another column to disanbiguate the resultset (ie some value that is unique amongst each group of records having the same id_user), say id, here is a solution to your question, that uses a self-join with ROW_NUMBER() to locate the third record in each group.
DELETE i
FROM items i
INNER JOIN (
SELECT
id,
id_user,
ROW_NUMBER() OVER(PARTITION BY id_user ORDER BY id) rn
FROM items
) c ON c.id = i.id AND c.id_user = i.id_user AND c.rn = 3
WHERE i.id_user=1 ;
Demo on DB Fiddle
You didn't provide the definition of your table. I guess it has a primary key column called id.
In that case you can use this
CREATE TEMPORARY TABLE doomed_ids
SELECT id FROM Items WHERE id_user = 1 ORDER BY id_user LIMIT 2,1;
DELETE FROM Items
WHERE id IN ( SELECT id FROM doomed_ids);
DROP TABLE doomed_ids;
It's a pain in the neck, but it works around the limitation of MySQL and MariaDB disallowing LIMITs in ... IN (SELECT ...) clauses.
You can use the select query to create a derived table and join it back to your main table to determine which record(s) to delete. Derived tables can use the limit clause.
Assuming that the PK is called id, the query would look as follows:
delete i from items i
inner join (SELECT id FROM Items
WHERE id_user=1
ORDER BY id_user LIMIT 2,1) i2 on i.id=i2.id
You need to substitute your PK in place of id. If you have a multi-column PK, then you need to select all the PK fields in the derived table and join on all of them.
I'm trying to update the last inserted record and assign to it's column - campaign_id the value in id (same record).
i came up with this query :
UPDATE campaigns
SET campaign_id= (select id order by id desc LIMIT 1)
WHERE id = (select id order by id desc LIMIT 1)
but for some reason i can't understand it updated the ENTIRE table, why is that?
I think the following is what you were intending to do:
UPDATE campaigns
SET campaign_id = id
WHERE id = (SELECT id FROM campaigns ORDER BY DESC LIMIT 1);
Whether or not this be logically correct depends on whether the record with the max id is actually the latest record. I can imagine that not being the case, but perhaps the logic in the above subquery could be changed to cover this possibility.
Consider a table like this:
The id column is set to auto-increment, update_time column is supposed to be the date that the row was inserted in the table.
I want to simply get the latest entry for a user with user_id = x, I found out there are some ways:
SELECT * FROM mytable WHERE user_id = x ORDER BY update_time DESC LIMIT 1
And
SELECT * FROM mytable WHERE user_id = x MAX(update_time)
And another query would be selecting the row with highest id number
I am not quite sure about the syntax of the later one (please correct me).
This may seem to be a trivial task, but there was a case that someone else has altered the auto_increment value on the table, and sometimes the time of the server has changed (well this has not been happened in my case but what if it does!!?)
What would be the safest query to get the latest entry row for a user_id ( I mean a query to return weigh, height and activity_level for a user with user_id = x)
Do I need to add more columns to the table? if so, what?
I like the join approach for this. Assumes that userID + update_time is unique...it'll pull back multiple rows if it isn't.
select user_id, max(update_time) maxtime from table group by user_id
Simple statement to get the max update time by user ID. Use it as a subquery with inner join (inner join will function as a filter)
select t.*
from table t
inner join
(select user_id, max(update_time) maxtime
from table group by user_id
--where user_id = x
)a
on a.user_id = t.user_id and a.maxtime = t.update_time
I commented out the where user_id = x line...the advantage to this method is you can get all users and their most recent at once.
SELECT * FROM mytable WHERE user_id = x AND update_time = (SELECT MAX(update_time) FROM mytable WHERE user_id = x)
This really does not have to be so complicated:
SELECT id
FROM table
WHERE user_id = x
ORDER BY update_time DESC
LIMIT 1
This version will be the quickest, simplest, and easiest to read. It is a win in every regard.
I have the following MySQL statement
SELECT * FROM user_messages AS T WHERE user_id = '33' AND id = (SELECT Max(id) from user_messages AS TT WHERE T.from_userid = TT.from_userid) ORDER BY status, id DESC
The problem I seem to be having is when I only have one record. I would think that MySQL would return the single record associated with user_link = '33', but instead it returns nothing.
I need to use the "Max" function because I use it to pull the most recent entries. I am trying to avoid having multiple queries or having to use php to sort also. Any help much appreciated!
This is your query:
SELECT *
FROM user_messages AS T
WHERE user_id = '33' AND
id = (SELECT Max(id)
from user_messages AS TT
WHERE T.from_userid = TT.from_userid
)
ORDER BY status, id DESC
Here are three reasons it could be failing to return any rows. First, user_id = '33' may not exist in the table. Second from_userid may be NULL. Third, the id value may be NULL for all matching records.
Perhaps this simpler version would help:
select *
from user_messages um
where user_id = '33'
order by id desc
limit 1
Thanks for your answer Gordon, I checked the database, and the record exists. I did some more research, and what it turns out to be is that I needed to join the data. I was able to return the Min or Max record, but the corresponding/related fields weren't returned with it.
SELECT * FROM user_messages INNER JOIN(SELECT from_username, MAX(id) AS id FROM user_messages WHERE user_link = '33' GROUP BY from_username ORDER BY status, id DESC) t2 ON user_messages.id = t2.id AND user_messages.from_username = t2.from_username
The thread that answered the question was this one - Need To Pull Most Recent Record By Timestamp Per Unique ID
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)