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)
Related
Im currently working on a project that requires MySql database and im having a hard time constructing the query that i want get.
i want to get the previous 10 rows from the specific WHERE condition on my mysql query.
for example
My where is date='December';
i want the last 10 months to as a result.
Feb,march,april,may,june,july,aug,sept,oct,nov like that.
Another example is.
if i have a 17 strings stored in my database. and in my where clause i specify that WHERE strings='eyt' limit 3
Test
one
twi
thre
for
payb
six
seven
eyt
nayn
ten
eleven
twelve
tertin
fortin
fiftin
sixtin
the result must be
payb
six
seven
Thanks in advance for your suggestions or answers
If you are using PDO this is the right syntax:
$objStmt = $objDatabase->prepare('SELECT * FROM calendar ORDER BY id DESC LIMIT 10');
You can change ASC to DESC in order to get either the first or the last 10.
Here's a solution:
select t.*
from mytable t
inner join (select id from mytable where strings = 'eyt' order by id limit 1) x
on t.id < x.id
order by t.id desc
limit 3
Demo: http://sqlfiddle.com/#!9/7ffc4/2
It outputs the rows in descending order, but you can either live with that, or else put that query in a subquery and reverse the order.
Re your comment:
x in the above query is called a "correlation name" so we can refer to columns of the subquery as if they were columns of a table. It's required when you use a subquery as a table.
I chose the letter x arbitrarily. You can use anything you like as a correlation name, following the same rules you would use for any identifier.
You can also optionally define a correlation name for any simple table in the query (like mytable t above), so you can refer to columns of that table using a convenient abbreviated name. For example in t.id < x.id
Some people use the term "table alias" but the technical term is "correlation name".
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.
I have the following query:
SELECT vBrowser,iconBrowser, count(iconBrowser) as 'N'
FROM user_ip_tmp WHERE code='9m9g9tsv2y'
GROUP BY iconBrowser
ORDER BY N DESC
LIMIT 40
And this works properly. But the delirious cause query took a long time.
Showing rows 0 - 17 ( 18 total, Query took 4.4189 sec)
Things that are in WHERE statement, should be indexed.
Try to use EXPLAIN statement before your SELECT to see what and how is used to retrief your requested results.
And if the column code is not an unique value, i would recommend to put it in some other table, where it is unique. Then build the query using JOIN though the FOREIGN KEY.
In a MySQL table, I would like to take 10 records with DISTINCT values.
I am using Zend Framework.
$select = $this->getAdapter()->select()
->from('table', 'column')->group('column')
->limit(10, 0);
This is the query generated by the above code.
SELECT table.column FROM
table GROUP BY column LIMIT 10
What happens here is that MySQL is taking 10 records first and then applying the group by. So finally, I am getting only 7 records.
How to apply DISTINCT first and then take 10 records from it?
Test that SQL against a table -- MySQL applies the limit last, so doesn't do what you're saying. eg test against
a0 a1
1 1
2 1
3 2
4 2
and do select A.a1 from A group by a1 limit 2. You should see 1, 2, not 1, 1.
[I wanted to say this as a 'comment' rather than an 'answer', but couldn't]
I'm not 100% sure what you are trying to do.
But if i am reading it correct you need 10 records with a certain criteria and then apply the group. not the other way around.
Can't you use WHERE in this case?
SELECT table.column FROM table WHERE "criteria" GROUP BY column LIMIT 10
Regards
Mike
This may help you (I didn't test it but so I'm not sure it's working)
SELECT DISTINCT column FROM table LIMIT 10
If it's not working, you may use a temporary table (like (SELECT column FROM table) TEMP), which will select the distinct elements, then a query which will select the first ten results into this table.
Hope this'll help :)
In ZF, You should use distinct() method into Your query chain :
$select = $this->getAdapter()->select()
->distinct()
->from('table', 'column')
->limit(10, 0);
SELECT DISTINCT column
FROM table
LIMIT 10
GROUP BY column
Not sure how to get it into classes though...
I have a mysql database. How do I select the most recent 10 records? Im not storing timestamps. But the most the recent records are the ones at the bottom rite? Also. How so I get the next ten , the next ten and so on on clicking a button. Kinda like a bunch of forum posts. The recent ones show up first.
I believe you have an auto increment column as a primary key you can use this column and to order by desc
select * from table order by id desc limit 10
otherwise you have a very poor database design
If you have an AUTO_INCREMENT column you can order by that in descending order then limit by 10.
But I suggest you store timestamps and order by that instead so you know you're sorting your records according to date, and not some other value that coincides with date of insertion.
In addition to what #BoltClock mentioned, prequerying the maximum ID might help the engine with what other records are retrieved... ie: if you have a million records, and most recent 10, I don't know if it will still try to query out the million, order them, and THEN dump it.. I would try something like
select STRAIGHT_JOIN
YT.*
from
( select max( IDColumn ) as MaxOnFile
from YourTable ) PreQuery,
YourTable YT
where
YT.IDColumn >= PreQuery.MaxOnFile -10
order by
YT.IDColumn DESC
limit 10
However, if for some reason, records are allowed to be deleted, you may opt to subtract a little farther back than the -10... but at least this way, the system won't even TRY to process all the other records...