views:

23

answers:

3

Okay, this is (probably) a very simple question, but I am afraid I know almost no MySQL, so please put up with me. I'm just trying to delete every row from one table which is not constrained by a Foreign Key in another table - a specific table, there are only two tables involved here. The create statements look a bit like:

CREATE TABLE  `testschema`.`job` (
  `Job_Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Comment` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`Job_Id`) USING BTREE,
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE  `ermieimporttest`.`jobassignment` (
  `JobAssignment_Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `JobId` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`JobAssignment_Id`),
  KEY `FK_jobassignment_1` (`JobId`),
  CONSTRAINT `FK_jobassignment_1` FOREIGN KEY (`JobId`) REFERENCES `job` (`Job_Id`),
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

Any my SQL statement is:

DELETE FROM job USING job INNER JOIN jobAssignment WHERE job.Job_Id != jobAssignment.JobId;

I thought this was correct - it should delete every job from the job table for which there does not exist a job assignment which has that job as it's Foreign Key. However, this fails with the following error when I try and execute it:

Cannot delete or update a parent row: a foreign key constraint fails (testdatabase.jobassignment, CONSTRAINT FK_jobassignment_1 FOREIGN KEY (JobId) REFERENCES job (Job_Id))

So what silly thing am I doing wrong?

EDIT: As usual, I found an answer only seconds after posting here. I used the (completely different) query:

DELETE FROM job WHERE Job_Id NOT IN (SELECT JobId FROM jobassignment) 

Out of curiosity, is this the better way to do it? Was my original idea even feasible? And if so, what was wrong with it?

+2  A: 
DELETE FROM job USING job 
LEFT JOIN jobAssignment ON(job.Job_Id = jobAssignment.JobId)
WHERE jobAssignment.JobId IS NULL;
Naktibalda
I choose this as the answer because it is the answer to my question of how to do the delete using a join. Although I did actually use Jaymz's answer, I found it indepedently of using it here, so while I give my graditude to him, this is the closer answer to my final question. Thanks, Naktibalda.
Stephen
+2  A: 

You'll probably need a subquery, not sure if this will work in mySQL, but something similar at least:

DELETE FROM job
WHERE job.Job_Id NOT IN (
  SELECT JobId FROM jobAssignment
)
Jaymz
Thanks. I'm afraid I choose Naktibalda's answer for the 'correct' answer because it answered my edited question the closest, but this solution was the one I actually found and used first! Thanks Jaymz.
Stephen
+1  A: 

Naktibalda suggests the subquery may be inefficient; if so you could try

DELETE FROM job
     WHERE NOT EXISTS (SELECT *
                           FROM jobassignment
                           WHERE job.Job_Id = jobassignment.Job_Id);

I've had bad experiences with IN and NOT IN in the past; less trouble with NOT EXISTS.

Brian Hooper
Thanks for the suggestion - the subquery approach did run in < 1 second (at least, I think - at the most it wasn't a noticeable pause) for 6500 rows, but I know that when it comes to databases there can be alot more rows than that quite easily!
Stephen