Update a set of records based on count - MySQL - php

I have a 100 active records in my table - cars. The user has decided to downgrade their account and is now eligible to only have 5 active records. I need to set the expiration date on 95 records (oldest first) to current timestamp. How do I do this in MySQL - bonus thanks if you include some cakephp hints (but I will thank you for just the SQL hint alone)
Here is what I tried but I get an error message stating that mySQL does not support LIMIT in sub-query
UPDATE cars
SET archived = NOW()
WHERE id NOT IN (
SELECT id
FROM cars
ORDER BY created DESC LIMIT 5
)

The MySQL documentation does not explain why LIMIT clauses in this type of subquery is not supported. However, there is no such limitation on sub-subqueries.
To resolve this issue, lets create another subquery and move the LIMIT clause into it:
WHERE id NOT IN (
SELECT id
FROM (
SELECT id
FROM cars
ORDER BY created
DESC LIMIT 5
)
AS carsInner
)
The innermost query will select only the last five rows, and exists only to satisfy the requirement that the subquery should not contain the limit clause.
The final query looks like:
UPDATE cars
SET `archived` = NOW()
WHERE id NOT IN (
SELECT id
FROM (
SELECT id
FROM cars
ORDER BY created
DESC LIMIT 5
)
AS carsInner
);
See an SQL Fiddle demo here.

Related

how to get next/previous records in mysql based on timestamp

I was wondering how to select next and previous rows from a mysql database with reference to my currently selected row.
I found this question on SO How to get next/previous record in MySQL? but in this case the select is done based on higher and lower id from the reference. I would like to use earlier or later timestamp instead of ids.
There is no reason for using subqueries.
Next:
SELECT * FROM `my_table`
WHERE `the_timestamp` > 123456
ORDER BY `the_timestamp` ASC
LIMIT 1
Prev:
SELECT * FROM `my_table`
WHERE `the_timestamp` < 123456
ORDER BY `the_timestamp` DESC
LIMIT 1
Based on the article you linked to, you can use:
SELECT *
FROM `my_table`
WHERE `the_timestamp` = (
SELECT MIN(`the_timestamp`)
FROM `my_table`
WHERE `the_timestamp` > 1373493634
);
It's formatted for readability. Replace the timestamp I used (1373493634) with the timestamp you want to find the next record after.

mysql check userID of last x posts

I have a php chat script on my site that I made, and I want to add in an anti-spam measure so that it wont post your message if the last 5 messages in the mysql table are by you.
Do I have to cycle through the last 5 with a recordset or is there a SQL statement that can just check this for me?
the table fields are just 'date' 'text' 'userid'
You can use a query like this to get how many of the last 5 messages where by the person in question.
select
sum(if(userid = '$user_id',1,0)) = 5
from (
select userid from chat order by id desc limit 5
);
In MySQL:
select userid, count(date) as howmany from
(
select userid, date
from YOURTABLENAME
order by date desc
limit 5
)
lastfiverows
group by userid
order by howmany
Then in PHP check to see if the "howmany" field is five, and the userid matches the user in question.
Order the record set (ORDER BY) by date (DESC) and LIMIT it to 5

Deleting all but the last 30 rows in database table with MySQL

I have simple question. How can I delete all but the last 30 rows in a database table? For example, take the following query:
DELETE FROM Comments
WHERE got='$user_id'
What else do I need to do in order to keep the last 30 rows?
This is what the Comments table looks like:
If your version if MySQL supports limits within sub-queries, then you can use a sub-query that selects the 30 most recent rows. Then, you can delete everything except those rows which were found in the sub-query.
DELETE
FROM Comments
WHERE got='$user_id'
AND got NOT IN
(SELECT got
FROM Comments
ORDER BY TIMESTAMP DESC LIMIT 30)
If your MySQL version does not support limits within sub-queries, then you'll need to split it up into two separate queries:
QUERY 1
SELECT got FROM Comments WHERE got='$user_id' ORDER BY TIMESTAMP DESC LIMIT 30
The results of query 1 should be stored in a single string variable (using the format 1,2,3...) and passed into query 2. (The explode and implode functions may come in handy when formatting the string.)
QUERY 2
DELETE
FROM Comments
WHERE got='$user_id'
AND got NOT IN ($formatted_result_from_query_1)
Store the last 30 rows in a temporary table and then exclude those rows from your delete:
CREATE TEMPORARY TABLE tmp AS (SELECT id FROM Comments WHERE got="$user_id" ORDER BY timestamp DESC LIMIT 5);
DELETE FROM Comments
WHERE got="$user_id" AND NOT EXISTS (SELECT id FROM tmp)
You can use LIMIT to do so:
DELETE c1
FROM Comments AS c1
LEFT JOIN
(
SELECT id
FROM comments
WHERE got = ...
ORDER BY id DESC
LIMIT 30
) AS c2
WHERE c2.id IS NULL;
See it in action here:
SQL Fiddle Demo (I just tried it with 5 rows only, with a simplified schema for your table)

MySQL Query to choose all but the most recent datetime

I have a row in my db table that is datetime. How can i write a query to only all rows except one (the most recent).
I would have used
ORDER BY col_name DESC LIMIT 1
if i was choosing only the most recent.. but i actually require all but the most recent.
Thanks
Just select all rows but the first:
ORDER BY col_name DESC LIMIT 1, 18446744073709551615
See 13.2.9. SELECT Syntax which explains the LIMIT clause.
Title says:
MySQL Query to choose all but the most recent datetime
If have duplicated dates you'll have to go for:
select * from t
where val != (select max(val) from t);
This is because if there are 2 max values then limit will only filter the first one and you'll get the other max value in the resultset.

How to upgrade next/previous record in mysql

mysql fetch previous or next record order by anyother field name and not by using order by id
select * from table where id > $id order by name asc limit 1
select * from table where id < $id order by name desc limit 1
I am able to get next and previous records but in this case how can i
upgrade next and previous records.
ID Links orderID
14 Google.com 1
15 Yahoo.com 2
20 gmail.com 3
25 facebook.com 4
What about if i use + and - button in front each link to upgrade and downgrade them and then rearrange the menus order by orderID ?
Well, if you really want to do it in a single query, you can use a subquery to find out the ID you need to update. The problem lies in the fact that MySQL cannot update the same table that you're trying to subquery, for obvious data integrity reasons. So you'll need to use some workarounds for that, such as creating a temporary table in a subquery.
UPDATE table AS t
SET [...]
WHERE t.`id` = (select * FROM (select `id` from table where `id` > $id order by `id` asc limit 1) AS sq)
There is absolutely no need to do the two selects.
You can do the following:
UPDATE table SET field='some value' WHERE id=$id+1
UPDATE table SET field='some value' WHERE id=$id-1
There you go :)

Categories