Delete - I can't specify target table? - mysql

Why this query doesn't work?
DELETE FROM recent_edits
WHERE trackid NOT IN
(SELECT DISTINCT history.trackid
FROM history JOIN recent_edits ON history.trackid=recent_edits.trackid
GROUP BY recent_edits.trackid)
I get this message : "You can't specify target table "recent_edits" for update in FROM clause

Try in this way
DELETE FROM recent_edits
WHERE trackid NOT IN
(select * from (SELECT DISTINCT history.trackid
FROM history JOIN recent_edits ON history.trackid=recent_edits.trackid
GROUP BY recent_edits.trackid) as t);

You can't post-process a table which is locked for deletion. using the hack select * from (query) as Nicola states will generate a temporary table instead of direct access.
Edit - make sure that you give ID to the tables you use since it is nested and will require uniqueID for every table.

Related

MySQL 5.7 remove duplicate rows in the same table based on multiple columns

I have a table with already existing records, I want to add a Unique constraint on multiple columns(app_instance_config_uuid, external_resource_id and spaceId), but first, I need to remove already existing duplicates.
This is an example of the table I want to add the constraint.
The best solution i found is
DELETE FROM spaces_apps
WHERE id IN ( SELECT id FROM ( SELECT MIN(id) AS id FROM spaces_apps
GROUP BY spaceId, app_instance_config_uuid, external_resource_id
HAVING COUNT(id) > 1 ) temp )
but the issue is that it only deletes one duplicate and if I need to delete more then one i need to run it again.
Important note that this is MySQL5.7 so using ROW_COUNT() and similar approaches doesn't work.
UPDATE:
The first solution works even better when just changing IN to NOT IN and removing the HAVING clause! Thanks to #Pankaj for pointing this!
DELETE FROM spaces_apps
WHERE id IN ( SELECT id FROM ( SELECT MIN(id) AS id FROM spaces_apps
GROUP BY spaceId, app_instance_config_uuid, external_resource_id )temp )
I found solution for this. It's not the prettiest but it's the only one that works in my case.
DELETE t1 FROM table_name t1
INNER JOIN table_name t2
WHERE
t1.created_at < t2.created_at AND
t1.app_instance_config_uuid=t2.app_instance_config_uuid AND
t1.external_resource_id=t2.external_resource_id AND
t1.spaceId=t2.spaceId;

Identifying values that are not existent in other table

I've got two tables that have one to many associations on a pmid. So if one table has an pmid, the second table should have multiple rows with the same pmid. However, something went sideways and I'm missing my latest batch of pmids in the second table. These queries, should help illustrate the problem, but I can't figure out how to get the ids from the first table that are actually missing in the second table.
select count(*) from abstract_mesh am; #2167101
select count(*) from abstract_mesh am
join abstracts a on am.pmid = a.pmid; #2133848
select 2167101 - 2133848; #33253
select count(*) from abstract_mesh where pmid is NULL; #33253
So as you can see there are 33,253 rows in abstract_mesh that have no pmids. I simply want to identify which pmids I should be interested in from the abstracts table.
You can use NOT EXITS to filter out the records, e.g.
select *
from table1 t1
where not exists
select * from table2 t2 where t1.pmid = t2.pmid;
You need and anti-join. SQL lacks an explicit anti-join operator. Standard SQL has EXCEPT (relational minus) by mySQL lacks this. Here I'm using NOT IN <table expression> to simulate anti-join (though not 100% sure I have the tables the right way round):
SELECT DISTINCT pmid
FROM abstract_mesh
WHERE pmid NOT IN ( SELECT pmid FROM abstracts );

select from database table rows that are not in another table

I have a table of 'entries' in a MYSQL database. I have another table that records activity on those entries, with the id of the entry as a foreign key. I want to select from my first table entries that do not appear in the second table.
How can I use SQL to make this happen? Do I have to iterate through both tables and compare every entry with every other entry? Is there an easier way to do this?
ex. I have a table with an entry data column and a user name column. I have another table with an entry id column and a user id column. I want to select from my first table all of the entries which do not appear in the second table with a given user id.
Thanks ahead of time. I have been struggling with this experiment for a while. I imagine I have to join the two tables somehow?
Several ways to achieve this, NOT IN, NOT EXISTS, LEFT JOIN / NULL check. Here's one with NOT EXISTS:
SELECT *
FROM FirstTable T
WHERE NOT EXISTS (
SELECT *
FROM SecondTable T2
WHERE T.Id = T2.Id
)
From what I understand, you want to select all rows where the foreign key doesn't match anything in the other table. This should do the trick:
SELECT *
FROM Data A
RIGHT JOIN Entry B
ON A.ID = B.ID
WHERE A.ID IS NULL
Here's a handy chart that illustrates how to use joins for stuff like this.
You can also use NOT IN, and the mechanics for this one are actually a bit easier to understand.
SELECT *
FROM Data A
WHERE A.ID NOT IN (SELECT ID FROM Entry)

Normalise data into one table

I'm trying to insert rows into a table (usersteps) from the table steps for all users only if the step id does not exist.
INSERT INTO userssteps
(status,user_id,step_id)
SELECT
'0' ,
(SELECT DISTINCT id from users),
(SELECT DISTINCT id from steps)
I get the following error on the above MYSQL
#1242 - Subquery returns more than 1 row
Reason:
A new user signs up they should get all steps, if I create a new step i'd want to create it in usersteps for current users to see.
If there is a more clever way to do this i'd love to know but i'm stumped. I am also using cakePHP so if there is a special cakePHP way to help me in this i'd prefer that.
Table Structure
steps:
id
name
users:
id
username
password
userssteps:
id
user_id
step_id
status
It looks like you are trying to produce a cartesian product. http://en.wikipedia.org/wiki/Cartesian_product.
If there is no relations between the users and steps table then they cannot be joined, only multiplied.
INSERT INTO userssteps
(status,user_id,step_id)
select 0,
users.id,
steps.id
from users
inner join steps
The subquerys (SELECT DISTINCT id from users) and (SELECT DISTINCT id from steps) will return ALL the id's. In a insert clause you will need only one value (you can't have more than 1 value).
you can try to inner join the two tables by the ID
Try this way:
INSERT INTO userssteps
(status,user_id,step_id)
select 0 as status,
users.id,steps.id
from users
inner join steps
on (users.id=steps.user_id);
That way should works ;)
PS: Now the join is right.
Saludos.

Deleting duplicate rows with sql

I am trying to delete duplicate rows from my mysql table. I've tried multiple queries but I am keep on getting this error: #1093 - You can't specify target table 'usa_city' for update in FROM clause
The table looks like this:
usa_city
--------
id(pk)
id_state
city_name
And the queries I have tired were:
DELETE FROM usa_city
WHERE id NOT IN
(
SELECT MIN(id)
FROM usa_city
GROUP BY city_name, id_state
)
And:
DELETE
FROM usa_city
WHERE usa_city.id IN
-- List 1 - all rows that have duplicates
(SELECT F.id
FROM usa_city AS F
WHERE Exists (SELECT city_name, id_state, Count(id)
FROM usa_city
WHERE usa_city.city_name = F.city_name
AND usa_city.id_state = F.id_state
GROUP BY usa_city.city_name, usa_city.id_state
HAVING Count(usa_city.id) > 1))
AND usa_city.id NOT IN
-- List 2 - one row from each set of duplicate
(SELECT Min(id)
FROM usa_city AS F
WHERE Exists (SELECT city_name, id_state, Count(id)
FROM usa_city
WHERE usa_city.city_name = F.city_name
AND usa_city.id_state = F.id_state
GROUP BY usa_city.city_name, usa_city.id_state
HAVING Count(usa_city.id) > 1)
GROUP BY city_name, id_state);
Thanks in advance.
Try to select the duplicates first, the delete them
DELETE FROM usa_city WHERE city_id IN
(
SELECT city_id FROM usa_city
GROUP BY city_name, id_state
HAVING count(city_id) > 1
)
Hope it helps!!!
MODIFIED: Based on the comment, if you want to keep one record, you can make a join and keep the lowest value
DELETE c1 FROM usa_city c1, usa_city c2 WHERE c1.id < c2.id AND
(c1.city_name= c2.city_name AND c1.id_state = c2.id_state)
Be sure to make a backup before executing the query above...
from mysql documentation:
"Currently, you cannot delete from a table and select from the same
table in a subquery."
but here is a workaround for update, should work for delete too.
also, you could select rows, and then in php for example delete them in loop
You may found here an answer to your problem: How to delete duplicate records in mysql database?
You should improve your database by using keyfields to prevent duplicate rows, so you dont need to clear in future.
Edit : This solution is also found if you follow the link posted by BloodyWorld, so if it works please go and upvote DMin's post here
Found this browsing the internet (#1 google result for mysql delete duplicate rows), have you tried it?
delete from table1
USING table1, table1 as vtable
WHERE (NOT table1.ID=vtable.ID)
AND (table1.field_name=vtable.field_name)
Judging from your examples, when you say "duplicate", you mean "having the same combination of id_state and city_name", correct? If so after you have done removing the duplictes, I strongly suggest creating a UNIQUE constraint on {id_state, city_name}.
To actually remove the duplicates, it is not enough to just identify the set of duplicates, you must also decide which of the identified duplicates to keep. Assuming you want to keep the ones with the smallest id, the following piece of SQL will do the job:
CREATE TEMPORARY TABLE usa_city_to_delete AS
SELECT id FROM usa_city T1
WHERE EXISTS (
SELECT * FROM usa_city T2
WHERE
T1.id_state = T2.id_state
AND T1.city_name = T2.city_name
AND T1.id > T2.id
);
DELETE FROM usa_city
WHERE id IN (SELECT id FROM usa_city_to_delete);
DROP TEMPORARY TABLE usa_city_to_delete;
Unfortunately, MySQL does not allow the correlated subqueries in DELETE, otherwise we could have done that in a single statement, without the temporary table.
--- EDIT ---
You can't have a correlated subquery but you can have JOIN, as illustrated by Carlos Quijano answer. Also, the temporary table can be created implicitly, as suggested by Kokers.
So it is possible to do it in a single statement, contrary to what I wrote above...