MySQL DELETE FROM с подзапросом в качестве условия
Я пытаюсь сделать запрос, как это:
DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015
);
Как вы, вероятно, можете сказать, я хочу удалить родительское отношение к 1015, если у того же тида есть другие родители. Тем не менее, это дает мне синтаксическую ошибку:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS th
WHERE th.parent = 1015 AND th.tid IN (
SELECT DISTINCT(th1.tid)
FROM ter' at line 1
Я проверил документацию и сам запустил подзапрос, и все это, похоже, подтвердилось. Кто-нибудь может понять, что здесь не так?
Обновление: как указано ниже, MySQL не позволяет использовать таблицу, из которой вы удаляете, в подзапросе для условия.
8 ответов
Вы не можете указать целевую таблицу для удаления.
Обходной путь
create table term_hierarchy_backup (tid int(10)); <- check data type
insert into term_hierarchy_backup
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015;
DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);
Для тех, кто считает этот вопрос удаляемым при использовании подзапроса, я оставляю вам этот пример для перехвата MySQL (даже если некоторые люди считают, что это невозможно):
DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
FROM tableE
WHERE arg = 1 AND foo = 'bar');
выдаст вам ошибку:
ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause
Однако этот запрос:
DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
FROM (SELECT id
FROM tableE
WHERE arg = 1 AND foo = 'bar') x);
будет работать просто отлично
Query OK, 1 row affected (3.91 sec)
Сверните ваш подзапрос в дополнительный подзапрос (здесь он называется x), и MySQL с радостью выполнит то, что вы просите.
Псевдоним должен быть включен после DELETE
ключевое слово:
DELETE th
FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN
(
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015
);
Вам нужно снова сослаться на псевдоним в операторе удаления, например:
DELETE th FROM term_hierarchy AS th
....
Я подошел к этому немного по-другому, и это сработало для меня;
Мне нужно было удалить secure_links
из моего стола, который ссылался на conditions
таблица, в которой больше не осталось строк условий. Домашний сценарий в основном. Это дало мне ошибку - Вы не можете указать целевую таблицу для удаления.
В поисках вдохновения я пришел к следующему запросу, и он прекрасно работает. Это потому, что он создает временную таблицу sl1
это используется в качестве ссылки для удаления.
DELETE FROM `secure_links` WHERE `secure_links`.`link_id` IN
(
SELECT
`sl1`.`link_id`
FROM
(
SELECT
`sl2`.`link_id`
FROM
`secure_links` AS `sl2`
LEFT JOIN `conditions` ON `conditions`.`job` = `sl2`.`job`
WHERE
`sl2`.`action` = 'something' AND
`conditions`.`ref` IS NULL
) AS `sl1`
)
Работает для меня.
Не является ли предложение in в delete... крайне неэффективным, если из подзапроса будет возвращено большое количество значений? Не уверен, почему бы вам не просто выполнить внутреннее (или правое) соединение с исходной таблицей из подзапроса по идентификатору для удаления, а не с помощью "in (подзапроса)".?
DELETE T FROM Target AS T
RIGHT JOIN (full subquery already listed for the in() clause in answers above) ` AS TT ON (TT.ID = T.ID)
И, возможно, на него дан ответ в "MySQL не разрешает это", однако, он работает нормально для меня. ПРЕДОСТАВЛЕНО, я уверен, чтобы полностью уточнить, что удалять (УДАЛИТЬ T ИЗ Target AS T). Delete with Join in MySQL проясняет проблему DELETE / JOIN.
Если вы хотите сделать это с 2 запросами, вы всегда можете сделать что-то похожее на это:
1) возьмите идентификаторы из таблицы с:
SELECT group_concat(id) as csv_result FROM your_table WHERE whatever = 'test' ...
Затем скопируйте результат с помощью мыши / клавиатуры или языка программирования в XXX ниже:
2) DELETE FROM your_table WHERE id IN ( XXX )
Может быть, вы могли бы сделать это в одном запросе, но это то, что я предпочитаю.
Вы можете использовать псевдоним таким образом в операторе удаления
DELETE th.*
FROM term_hierarchy th
INNER JOIN term_hierarchy th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th.parent = 1015;
@CodeReaper, @BennyHill: все работает как положено.
Тем не менее, мне интересно, сложность времени для миллионов строк в таблице? Видимо, потребовалось около 5ms
выполнить для 5k записей в правильно проиндексированной таблице.
Мой запрос:
SET status = '1'
WHERE id IN (
SELECT id
FROM (
SELECT c2.id FROM clusters as c2
WHERE c2.assign_to_user_id IS NOT NULL
AND c2.id NOT IN (
SELECT c1.id FROM clusters AS c1
LEFT JOIN cluster_flags as cf on c1.last_flag_id = cf.id
LEFT JOIN flag_types as ft on ft.id = cf.flag_type_id
WHERE ft.slug = 'closed'
)
) x)```
Or is there something we can improve on my query above?