Удалить с Join в MySQL

334
CREATE TABLE `clients` (
   `client_id` int(11),
   PRIMARY KEY (`client_id`)
);
CREATE TABLE `projects` (
   `project_id` int(11) unsigned,
   `client_id` int(11) unsigned,
   PRIMARY KEY (`project_id`)
);
CREATE TABLE `posts` (
   `post_id` int(11) unsigned,
   `project_id` int(11) unsigned,
   PRIMARY KEY (`post_id`)
);

В моем PHP-коде при удалении клиента я хочу удалить записи всех проектов:

DELETE 
FROM posts

INNER JOIN projects 
  ON projects.project_id = posts.project_id

WHERE projects.client_id = :client_id;

Таблица сообщений не имеет внешнего ключа client_id, только project_id. Я хочу удалить сообщения, которые публикуются в проектах, имеющих пройденный client_id.

Это не работает прямо сейчас (никакие сообщения не удаляются).

  • 10
    Я думаю, что ответ Yehosef должен быть принят, так как он использует Join, как вы просили, и что он работает лучше, чем использование предложения IN, как предложил yukondude ...
  • 2
    Предпочтительным шаблоном является DELETE posts FROM posts JOIN projects ... , а не IN (subquery) . (Ответ от Yehosef приводит пример предпочтительного шаблона.)
Показать ещё 2 комментария
Теги:

13 ответов

885
Лучший ответ

Вам просто нужно указать, что вы хотите удалить записи из таблицы posts:

DELETE posts
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

EDIT: для получения дополнительной информации вы можете увидеть этот альтернативный ответ

  • 110
    Следует отметить, что это правильный ответ, поскольку объединение заставляет вас использовать «УДАЛИТЬ сообщения из сообщений» вместо обычных «УДАЛИТЬ ИЗ сообщений», поскольку таблица для удаления больше не является однозначной. Спасибо!
  • 8
    Обратите внимание, что здесь вы не можете использовать метод as, например, проекты внутреннего соединения как p для p.project_id ...
Показать ещё 16 комментариев
44

Или то же самое, с немного отличающимся (IMO более дружелюбным) синтаксисом:

DELETE FROM posts 
USING posts, projects 
WHERE projects.project_id = posts.project_id AND projects.client_id = :client_id;

Кстати, с mysql с помощью соединений почти всегда быстрее, чем подзапросы...

  • 0
    Что означает ИСПОЛЬЗОВАНИЕ?
  • 1
    Хорошее объяснение USING : stackoverflow.com/questions/11366006/mysql-on-vs-using
Показать ещё 1 комментарий
40

Поскольку вы выбираете несколько таблиц, таблица для удаления из уже не однозначна. Вам нужно выбрать:

delete posts from posts
inner join projects on projects.project_id = posts.project_id
where projects.client_id = :client_id

В этом случае table_name1 и table_name2 являются одной и той же таблицей, поэтому это будет работать:

delete projects from posts inner join [...]

Вы даже можете удалить из обеих таблиц, если хотите:

delete posts, projects from posts inner join [...]

Обратите внимание, что order by и limit не работают для удаления нескольких таблиц.

Также имейте в виду, что если вы объявляете псевдоним для таблицы, вы должны использовать псевдоним, когда ссылаетесь на таблицу:

delete p from posts as p inner join [...]

Вклад от Carpetsmoker и т.д..

  • 3
    Если вы делаете лучший ответ - по крайней мере, вы можете сделать SQL более читабельным. Все остальные ссылки на SQL в этом вопросе имеют заглавные слова (кроме одного с 0 голосами). Я не уверен, почему ты отменил мои правки.
  • 3
    @Yehosef, есть группа людей, которые считают, что CAPS действительно бросаются в глаза. Я верю, что я не единственный, я видел немало людей, которые тоже использовали строчные буквы.
Показать ещё 5 комментариев
37

Вы также можете использовать ALIAS, как это он работает, просто использовал его в моей базе данных! t нужно удалить таблицу из!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id
  • 1
    это полезно при соединениях составных ключей, чтобы избежать повторения имен таблиц
  • 1
    «На самом деле вы можете использовать псевдоним для объединяемых таблиц, но не для основной таблицы (записей). 'УДАЛИТЬ ЗАПИСИ ИЗ ПОЛОЖЕНИЙ ВНУТРЕННИЕ СОЕДИНЕННЫЕ ПРОЕКТЫ p ON p.project_id = posts.project_id'" - @ Weboide
Показать ещё 1 комментарий
21

Я больше привык к этому подзапросу, но я не пробовал его в MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );
  • 84
    Вы действительно должны избегать использования ключевого слова IN в SQL (хотя обычно это проще для начинающих) и использовать вместо этого JOIN (когда это возможно), так как подзапросы обычно делают вещи намного медленнее.
  • 14
    Это приводит к аварийному завершению работы базы данных, когда подзапрос возвращает огромное количество строк. Это также очень медленно.
Показать ещё 10 комментариев
10

MySQL УДАЛИТЬ записи с помощью JOIN

Обычно вы используете INNER JOIN в инструкции SELECT для выбора записей из таблицы с соответствующими записями в других таблицах. Мы также можем использовать предложение INNER JOIN с оператором DELETE для удаления записей из таблицы, а также соответствующих записей в других таблицах, например, для удаления записей из таблиц T1 и T2, удовлетворяющих определенному условию, вы используете следующий оператор:

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition

Обратите внимание, что вы помещаете имена таблиц T1 и T2 между DELETE и FROM. Если вы опускаете таблицу T1, оператор DELETE удаляет записи только в таблице T2, и если вы опускаете таблицу T2, удаляются только записи в таблице T1.

Условие соединения T1.key = T2.key указывает соответствующие записи в таблице T2, которые необходимо удалить.

Условие в предложении WHERE указывает, какие записи в T1 и T2 необходимо удалить.

7

Попробуйте сделать следующее:

DELETE posts.*,projects.* 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;
  • 3
    Какой смысл .* ?
5

Удаление отдельной таблицы:

Чтобы удалить записи из таблицы posts:

DELETE ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Чтобы удалить записи из таблицы projects:

DELETE pj 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Чтобы удалить записи из таблицы clients:

DELETE C
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Несколько таблиц Удалить:

Чтобы удалить записи из нескольких таблиц из объединенных результатов, вам нужно указать имена таблиц после DELETE как список, разделенный запятыми:

Предположим, что вы хотите удалить записи из всех трех таблиц (posts, projects, clients) для конкретного клиента:

DELETE C,pj,ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id
4
mysql> INSERT INTO tb1 VALUES(1,1),(2,2),(3,3),(6,60),(7,70),(8,80);

mysql> INSERT INTO tb2 VALUES(1,1),(2,2),(3,3),(4,40),(5,50),(9,90);

DELETE записи из одной таблицы:

mysql> DELETE tb1 FROM tb1,tb2 WHERE tb1.id= tb2.id;

УДАЛИТЬ ЗАПИСИ ИЗ обеих таблиц:

mysql> DELETE tb2,tb1 FROM tb2 JOIN tb1 USING(id);
3

Другим методом удаления с помощью подбора, который лучше, чем с использованием IN, будет WHERE EXISTS

DELETE  FROM posts
WHERE   EXISTS ( SELECT  1 
                 FROM    projects
                 WHERE   projects.client_id = posts.client_id);

Одной из причин использования этого вместо объединения является то, что DELETE с JOIN запрещает использование LIMIT. Если вы хотите удалить блоки, чтобы не создавать полные блокировки таблицы, вы можете добавить LIMIT этот метод DELETE WHERE EXISTS.

  • 1
    Может ли этот запрос быть написан с помощью «псевдонимов»? Из синтаксиса не очень понятно, как posts в EXISTS () - это те же posts , из которых удаляются строки. (ИМХО в любом случае)
  • 0
    Я слышал, но псевдонимы в таблице не могут быть удалены из. «Посты» в подзапросе должны быть полным именем таблицы, что означает, что если вы хотите повторно использовать эту таблицу в предложении подвыборки «От», вам нужно будет создать там псевдоним.
Показать ещё 1 комментарий
1

Если соединение не работает для вас, вы можете попробовать это решение. Он предназначен для удаления сиротских записей из t1, когда не используются внешние ключи + конкретные условия. То есть он удаляет записи из таблицы1, у которых есть пустой код "код" и которые не имеют записей в таблице2, сопоставляя по полю "имя".

delete table1 from table1 t1 
    where  t1.code = '' 
    and 0=(select count(t2.name) from table2 t2 where t2.name=t1.name);
0

Попробуйте это,

DELETE posts.*
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id
-4

- Обратите внимание, что вы не можете использовать псевдоним над таблицей, где вам нужно удалить

DELETE tbl_pagos_activos_usuario
FROM tbl_pagos_activos_usuario, tbl_usuarios b, tbl_facturas c
Where tbl_pagos_activos_usuario.usuario=b.cedula
and tbl_pagos_activos_usuario.cod=c.cod
and tbl_pagos_activos_usuario.rif=c.identificador
and tbl_pagos_activos_usuario.usuario=c.pay_for
and tbl_pagos_activos_usuario.nconfppto=c.nconfppto
and NOT ISNULL(tbl_pagos_activos_usuario.nconfppto)
and c.estatus=50

Ещё вопросы

Сообщество Overcoder
Наверх
Меню