Видалити за допомогою приєднатися до MySQL


501

Ось сценарій для створення моїх таблиць:

CREATE TABLE clients (
   client_i 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 має бути прийнятою, оскільки він використовує приєднатись так, як ви просили, і що він працює краще, ніж використання пункту IN, як запропонував yukondude ...
Джерардо Гріньолі

2
Кращий візерунок - це DELETE posts FROM posts JOIN projects ..., а не IN (subquery)візерунок. (Відповідь Єгосефа дає приклад бажаного шаблону.)
spencer7593

@GerardoGrignoli, чи працює вона краще для певного двигуна або версії MySQL? Немає жодної причини, щоб обидва запити виконувались по-різному, оскільки в AFAIK вони однакові. Звичайно, якби у мене був нікель щоразу, мій оптимізатор запитів робив щось дурне ....
Пол Дрейпер,

Ви також можете використовувати aliasдля назви таблиці та використовувати це.
бініям

Відповіді:


1253

Вам просто потрібно вказати, що ви хочете видалити записи з postsтаблиці:

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

EDIT: Для отримання додаткової інформації ви можете побачити цю альтернативну відповідь


117
Слід зазначити, що це правильна відповідь, тому що об'єднання змушує вас використовувати "ВИДАЛИТИ повідомлення від повідомлень" замість звичайних "ВИДАЛИТИ З публікацій", оскільки таблиця для видалення вже не є однозначною. Дякую!
siannopollo

8
Зауважте, що ви не можете використовувати метод "as" тут, наприклад, внутрішні проекти приєднання як p на p.project_id ...
zzapper

14
Насправді ви можете використовувати псевдонім для об'єднаних таблиць, але не для головної таблиці (дописів). "ВИДАЛИТИ повідомлення від публікацій INNER JOIN projects p ON p.project_id = posts.project_id"
Weboide


14
це найкраща відповідь, оскільки ви можете навіть видалити з обох таблиць однією дієюDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium

84

Оскільки ви вибираєте кілька таблиць, таблиця, яку потрібно видалити, вже не є однозначною. Вам потрібно вибрати :

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 голосами). Я не впевнений, чому ви відмінили мої зміни.
Yehosef

3
@Yehosef, Є група людей, які вважають CAPS дуже яскравим. Я вважаю, що я не єдиний, я також бачив досить багато людей, що йдуть у малому стилі.
Pacerier

1
досить чесно - я поважаю ваше право писати свою відповідь у стилі, який вам подобається;)
Yehosef

7
Щоб додати до дискусії з обмеженим шаблоном / без обмежень, правда, ви можете використовувати будь-який стиль, який вам подобається, але у своїй відповіді ви фактично змішуєте стилі, де вам зручно - ONвелика літера. Недосвідчені розробники можуть довести, що нормально бути безладним та непослідовним щодо стилю.
Відтінок

16
КЛЮЧОВІ СЛОВА КАПСУ не є яскравими. вони ставлять питання, які читаються;)
Сахем,

50

Або те саме, з дещо іншим синтаксисом:

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

BTW, з використанням mysql приєднання майже завжди є швидше, ніж підзапити ...


Що означає ВИКОРИСТАННЯ?
CMCDragonkai

1
Гарне пояснення USING: stackoverflow.com/questions/11366006/mysql-on-vs-using
bigtex777

10
@ bigtex777: Зауважте, що використання ключового слова в операторах SELECT мало пов'язане з тим самим ключовим словом у операторі DELETE. У SELECTs він визначає список стовпців, до яких слід приєднатись, тоді як у DELETEs - це список усіх таблиць приєднання
ivanhoe

42

Ви також можете використовувати 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
це корисно при поєднанні клавішних з'єднань, щоб уникнути повторення назв таблиць
Marquez

1
"Насправді ви можете використовувати псевдонім для об'єднаних таблиць, але не для головної таблиці (дописів)." ВИДАЛИТИ повідомлення від публікацій ВНУТРІШНІ ПРИЄДНАЙТЕСЯ p ON p.project_id = posts.project_id '"- @ Weboide
Jeaf Gilbert

2
Насправді (цитування від dev.mysql.com/doc/refman/5.0/en/delete.html ) "Якщо ви оголосили псевдонім для таблиці, ви повинні використовувати псевдонім при посиланні на таблицю: DELETE t1 FROM test AS t1, test2 WHERE ... ", тож використання псевдоніма добре.
Пітер Боуерс

25

Я більше звик до цього питання, але я не пробував його в MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );

85
Вам слід уникати використання ключового слова IN у SQL (навіть якщо це для початківців зрозуміло легше) та використовувати JOIN замість цього (коли це можливо), оскільки підзапити зазвичай роблять набагато повільніше.
користувач276648

14
Це має тенденцію до збоїв у БД, коли існує величезна кількість рядків, повернених підзапитом. Це також надзвичайно повільно.
Радж

2
@yukondude Дійсно, "IN" набагато простіше зрозуміти, ніж "ПРИЄДНАЙТЕСЬ" на 1-й, і тому люди, які не дуже знайомі з SQL, закінчуватимуть писати "IN" скрізь, тоді як вони могли б використовувати "JOIN", який працює краще ( або whooole набагато краще, залежно від запиту). Пам’ятаю, кілька років тому майже всі мої SQL запити переписував би хтось, хто насправді знав, як написати хороші запити. Ось чому я додав коментар, щоб уникнути "IN", щоб люди знали, що якщо можливо, вони повинні уникати його використання.
користувач276648

10
Сама причина, що я зайшов на цю сторінку, полягає в тому, що запит, який я написав із заявою IN, був собачим повільним. Однозначно уникайте прийнятої відповіді тут.
MikeKulls

4
Скільки років це питання, важливо знати, ЧОМУ ви повинні використовувати JOIN замість IN. Коли умова працює на рядок, він виконує цей запит всередині IN. Це означає, що якщо є 100 рядків, які потрібно перевірити, де БУДЕ, цей підзапит буде запущений 100 разів. Тоді як ПРИЄДНАННЯ працюватиме лише ОДНЕ Отже, оскільки ваш db стає все більшим і більшим, цей запит буде тривати довше і довше, щоб закінчити. @markus тільки тому, що щось не є критичним, не означає, що ви повинні написати неправильний код. Написавши це трохи краще, ви заощадите багато часу та головного болю в майбутньому. :)
RisingSun

11

MySQL DELETE записує приєднатися

Зазвичай ви використовуєте 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 потрібно видалити.


11

Видалення єдиної таблиці:

Щоб видалити записи з 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

Інший спосіб видалення з допомогою саб вибрати , що краще , ніж використання INбудеWHERE EXISTS

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

Однією з причин використовувати це замість з'єднання є те, що a DELETEз JOINзабороняє використовувати LIMIT. Якщо ви хочете видалити в блоках, щоб не створювати повних блоків таблиці, ви можете додати LIMITвикористовувати цей DELETE WHERE EXISTSметод.


1
Чи можна цей запит написати "псевдонімами"? З синтаксису не зовсім зрозуміло, наскільки параметр " postsEXISTS" () такий самий posts, з якого видаляються рядки. (IMHO все одно)
MattBianco

Я чую вас, але псевдоніми не дозволяють видаляти з таблиці псевдоніми. "Повідомлення" в підзапиті повинні бути повними іменами таблиці, а це означає, що якщо ви хочете повторно використовувати цю таблицю у підпункті "Вибір" із пункту "Вибір", вам доведеться її псевдонімом там.
Джим Клуз

1
Це працює:DELETE p FROM posts p WHERE EXISTS ( SELECT 1 FROM projects WHERE projects.client_id = p.client_id);
MattBianco

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

Зняти записи з однієї таблиці:

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

Зняти записи з обох таблиць:

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

1

Якщо приєднання не працює для вас, ви можете спробувати це рішення. Він призначений для видалення осиротілих записів із t1, коли не використовується зовнішні ключі + специфічна, де умова. Тобто він видаляє записи з table1, які мають порожнє поле "код" і не мають записів у table2, збігаючись з полем "name".

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


-3

- Зауважте, що ви не можете використовувати псевдонім над таблицею, де потрібно видалити

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.