Mysql is throwing sql error on ORDER BY clause - mysql

It is absolutely beyond my ideas why the following query is not working:
DELETE orig FROM revision AS orig JOIN (
SELECT id
FROM revision
GROUP BY id
HAVING COUNT(*) > 1
) AS joined ON orig.id = joined.id
WHERE orig.id=1
ORDER BY orig.delta ASC
LIMIT 1
The error is thrown on line 8, so the ORDER BY clause. However, I cannot see anything wrong with it (the table revision does have a column called delta). Moreover, changing DELETE orig to SELECT * results in a flawlessly working command.
Is it possible that the delta-column isn't loaded? Or what is causing this error?
edit
Ah okay, I didn't know that you cannot use ORDER BY with multiple rows on a DELETE query.
Well, what I am trying to accomplish is that I delete one row in my table, which has an id that occurs more than once (will be 5 in production) and has the lowest delta of all rows with that id.
I.e. I have two rows in the revision table, both with the same id. I now want to delete that row which has the lowest delta of the two. This should be scalable, so that I delete all rows (with the same id) but one (the one with the highest delta).

You can't use ORDER BY if you have multiple tables in your DELETE statement

I think this is what you are trying to do. It will delete only 1 row only if the (id,delta) combination has a unique constraint:
DELETE orig
FROM revision AS orig
JOIN
( SELECT MIN(delta) AS delta
FROM revision
WHERE id = 1
HAVING COUNT(*) > 1
) AS joined ON orig.delta = joined.delta
WHERE orig.id = 1 ;
To delete all rows (with same id) except the (say 5) rows with highest delta, you can use:
DELETE orig
FROM revision AS orig
JOIN
( SELECT delta
FROM revision
WHERE id = 1
ORDER BY delta DESC
LIMIT 1 OFFSET 4 -- select the 5th highest
) AS joined ON orig.delta < joined.delta -- then find the lower than that
WHERE orig.id = 1 ;

Related

Fetch entries in table from last using LIMIT a,b or limit offset

I want to fetch latest entries in a table that is containing more than 1,000,000 entries. I am using this query for an instance
SELECT id FROM tablea WHERE flag = "N" ORDER BY id LIMIT 510045,200;
and it gives me entries starting from 510045 and ending at 510245. Can MYSQL have something where I can get entries starting from 510245 to 510045. I mean fetching the data from the last and I don't want to fetch only 200 entries.
You should ORDER BY desc and, if you want, LIMIT for define how many entries you want.
Example:
SELECT id FROM tablea WHERE flag = "N" ORDER BY id DESC;
-- this will help to find the last entries
But if you want to have the latest entries that you didn't get in last query, you should always hold the value of the last ID, and use it as reference to next check.
Example (Supposing the last ID of the last query execution was 55304):
SELECT id FROM tablea WHERE flag = "N" WHERE id > 55304 ORDER BY id DESC;
If what you want is rows where the id is greater than 510245 just use the where condition
Select * FROM table WHERE flag = 'n' AND id > 510245
This should do it
As i understand your requirement . you may try it.
Select * FROM table WHERE flag = 'N' AND id > 510245 ORDER BY id
One more thing here is
The version i was working on was not supporting subquery containing LIMIT. So, #strawberry Thanks for giving me the hint to solve the question. But I used this sub query as inner join table(explained below)
SELECT id FROM tablea AS T1
INNER JOIN (SELECT id FROM tablea WHERE flag = "N" ORDER BY id LIMIT 510045,200) AS T2
WHERE T2._id = T1._id ORDER BY T2._id DESC;
This gave me the required results. Thanks everyone for your help !!

How to delete element without knowing it's id, just order in DB

I have database table requests:
+----+---------+-----------------+--------+
| id | user_id | bicycle_type_id | height |
+----+---------+-----------------+--------+
And one user can have many records in this table. Ofcourse those record will have different id's.
When i displaying (in front-end) list of items, it is independent from id column in database, so the list always starts from 1, then 2 ... and so on. So, as a function argument, i get array of ID's (which are id's in the List on front-end, not in the database. Like number in the sequence) of the records i need to delete.
Important - I CAN'T change front-end
How can i preform query to delete elements when i only know their id in ASC order (their sequence number), which are unrelated from actual id's in the table?
For example if you want to delete the 12th row in the table:
DELETE FROM requests ORDER BY id ASC LIMIT 1 OFFSET 11
To delete the 5th row:
DELETE FROM requests ORDER BY id ASC LIMIT 1 OFFSET 4
To delete the 34th row:
DELETE FROM requests ORDER BY id ASC LIMIT 1 OFFSET 33
I would advise you make a table copy and test on the copy first.
OR
Try the following and see if you get the right row that you want to delete.
SELECT FROM requests ORDER BY id ASC LIMIT 1 OFFSET 4
I don't believe MySQL supports OFFSET in the LIMIT clause for DELETE.
You can do this as:
delete requests r join
(select r2.*
from requests r2
order by id
offset 11 limit 1
) rr
on r.id = rr.id;
I would suggest a couple of things in addition:
Lock the entire table. Two deletes running at the same time could interfere with each other.
Ensure that id is auto-increment, so new values are always larger than previous values (hence, inserts won't interfere with deletes).

Sort by multiple duplicate rows, then delete

I have a query that I have been working on in phpmyadmin that sorts entries based on a duplicate geometric locations,
The Query looks like this:
SELECT *, COUNT(*) c
FROM `spatial_locations`
WHERE 1
GROUP BY x,y,z HAVING c > 1
ORDER BY `c` DESC
And it returns a proper result ordered by 'c'
What I would like to do is further expand upon this query to go through the results, and delete any entries where C > 10 ordered by date (basically make any entries to the system older than the most recent 10 go away)
Is this possible the way I am suggesting it or am I on the completely wrong track?
delete any entries where C > 10 .... with that do you to perform a DELETE operation (OR) just exclude those records from your SELECT resultset. If you just want to remove from select query resultset then you can probably just modify your HAVING condition saying
HAVING c <= 10
Well, to DELETE you can have those rows inserted in a TEMPORARY table and use that table instead like
CREATE TEMPORARY TABLE test AS
SELECT some_unique_id_column, COUNT(*) c
FROM `spatial_locations`
WHERE 1
GROUP BY x,y,z
HAVING c <= 10
ORDER BY `c` DESC
Then perform the DELETE operation like
DELETE FROM `spatial_locations`
WHERE some_unique_id_column IN (
SELECT some_unique_id_column FROM test);

MySQL Query - set auto number

I have a database with many entries, starting with ID 100000 and ending at ID 200000.
Now I'm trying to set the first and lowest ID to 1, and decrease on each next ID +1
So the new first ID would be 1, and the last and highest would be 99000 in that example.
Is there any mysql query, which updates the rows from a given number, and +1 for each next row?
You can use a row number query in update and join with same table but update id with row number result from joined result set
update t
join (
select id,#r:=#r+1 `row`
from t
cross join (select #r:=0) t1
) t2 on (t.id = t2.id)
set t.id = t2.row
Note: donot directly run this query on your production database first test it with a copy of your database if result is successful
then apply on production database
Fiddle Demo

update a random row from a table

I've got this code here:
UPDATE starinformation SET starOwner = -1 WHERE (
SELECT starinformation.starID
ORDER BY RAND( )
LIMIT 1
)
I want to update a random row from a table with information pulled from that table and only effect 1 row.
There are a lot of problems with this approach:
MySQL does not allow combining a modifying outer query with a selecting subquery to touch the same table
ORDER BY RAND() LIMIT 1 is a major performance killer: It will create an intermediate result of ALL rows - i.e. if your table contains 1 megarows, you will touch every single one of them.
My recommendation is to
allways have a sortable single-field PK
Run SELECT ROUND(RAND()*COUNT(*)) AS num FROM starinformation, returning $num
Run UPDATE starinformation SET starOwner = -1 ORDER BY [pk-field] LIMIT $num,1