Using SQL to perform unique delete
I have a few tables in MySQL like so:
A ---- A_has_B ---- B
(many to many) |
|
C ---- C_has_B-------
(many to many)
I need to delete rows from B given that:
- The row t开发者_如何学运维o be deleted are referenced in C_has_B by C.C_ID
- The row to be deleted are not referenced by other C.C_IDs in C_has_B
- The row to be delete is also not referenced in A_has_B
I am able to get all the rows to be deleted referenced by C.ID using:
DELETE * FROM C
JOIN C_has_B
ON(C.C_ID = C_has_B.C_ID)
JOIN B
on(C_has_B.B_ID = B.B_ID)
where C.C_ID = 1;
I am not too sure how I can implement the last 2 conditions. Is it even possible to do this with just 1 query?
You want to delete rows from B that are referenced only once in C_has_B and not referenced by A_has_B.
With subqueries:
DELETE B
FROM
B
JOIN
(
-- get rows from C_has_B that reference B_ID only once
SELECT B_ID, Count(*)
FROM C_has_B
GROUP BY B_ID
HAVING Count(*) = 1
)
as C_has_B_once
on (B.B_ID = C_has_B_once.B_ID)
WHERE
-- filter to rows not referenced by A_has_B
B.B_ID not in (
SELECT B_ID
FROM A_has_B
)
Without subqueries:
DELETE B
FROM
B
-- get rows from C_has_B that reference B_ID only once
-- (find 1 match via C_has_B1 and make sure there are no other C_IDs referencing the same B_ID via C_has_B2)
JOIN
C_has_B as C_has_B1
on (B.B_ID = C_has_B1.B_ID) and (A_has_B.B_ID = NULL)
LEFT JOIN
C_has_B as C_has_B2
on (C_has_B1.B_ID = C_has_B2.B_ID) and (C_has_B1.C_ID <> C_has_B2.C_ID)
-- filter to rows not referenced by A_has_B
LEFT JOIN
A_has_B
on (B.B_ID = A_has_B.B_ID) and (A_has_B.B_ID = NULL)
WHERE
-- exclude rows that join to C_has_B2
(C_has_B2.C_ID is NULL)
精彩评论