Использование SQL для уникального удаления - PullRequest
1 голос
/ 29 июля 2011

У меня есть несколько таблиц в MySQL, например, так:

A ---- A_has_B ---- B
    (many to many)  |
                    |
C ---- C_has_B-------
    (many to many)

Мне нужно удалить строки из B, если:

  • Ссылка на удаляемую строку в C_has_B указана C.C_ID
    • На удаляемую строку не ссылаются другие идентификаторы C.C_ID в C_has_B
    • Строка, подлежащая удалению, также не указана в A_has_B

Я могу получить все строки для удаления, на которые ссылается C.ID, используя:

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;

Я не слишком уверен, как я могу выполнить последние 2 условия. Возможно ли это сделать всего одним запросом?

1 Ответ

2 голосов
/ 29 июля 2011

Вы хотите удалить строки из B, на которые ссылаются только один раз в C_has_B и на которые нет ссылки A_has_B.

С подзапросами:

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
    )

Без подзапросов:

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)
...