Як видалити з декількох таблиць у MySQL?


116

Я намагаюся видалити відразу з кількох таблиць. Я трохи провів дослідження і придумав це

DELETE FROM `pets` p,
            `pets_activities` pa
      WHERE p.`order` > :order
        AND p.`pet_id` = :pet_id
        AND pa.`id` = p.`pet_id`

Однак я отримую цю помилку

Uncaught Database_Exception [1064]: у вас є помилка у вашому синтаксисі SQL; перевірте посібник, який відповідає вашій версії сервера MySQL, чи правильний синтаксис для використання поруч із 'p, pets_activitiespa ...

Я ніколи раніше не робив видалення хрестоподібної таблиці, тому зараз я недосвідчений і застряг!

Що я роблю неправильно?

Відповіді:


204

Використовуйте JOINу DELETEвиписці.

DELETE p, pa
      FROM pets p
      JOIN pets_activities pa ON pa.id = p.pet_id
     WHERE p.order > :order
       AND p.pet_id = :pet_id

Крім того, ви можете використовувати ...

DELETE pa
      FROM pets_activities pa
      JOIN pets p ON pa.id = p.pet_id
 WHERE p.order > :order
   AND p.pet_id = :pet_id

... видалити лише з pets_activities

Дивіться це .

Для одиночних вилучень таблиці, але з посилальної цілісності, є й інші способи зробити з EXISTS, NOT EXISTS, IN, NOT INі т.д. Але один вище , де ви вказуєте , з яких таблиці для видалення з псевдонімом , перш ніж FROMстановище ви можете отримати з кількох досить щільно плями легше. Я схильний звернутися до EXISTS99% випадків, і тоді є 1%, де цей синтаксис MySQL займає день.


7
Я спробував це "видалити все за 1 запит", приєднавшись до 6 великих таблиць (у всіх близько ~ 15k рядків), і запит знадобився 155 секунд, щоб видалити 63 рядки з 6 таблиць: O
Klemen Tušar

1
@cadman Це справжня правильна відповідь; можуть бути аргументи проти його використання, але це дуже корисно при нагоді
Сайман Крістіан

1
+1 Я погоджуюсь, що це справді правильна відповідь, оскільки питання було не "чи варто", а "як це зробити". Однак мені було б цікаво почути про 1%, тому що я не можу придумати єдиної ситуації, де це було б кращим.
Ерік Робертсон

2
@techouse, ти приєднався та фільтруєш індекси? 15k x 15k x 15k x 15k 15k x 15k - це 11 мільйонів. Невже SELECTтривали подібні?
Пол Дрейпер

6
Ви також можете використовувати LEFT JOIN, що корисно, якщо в другій таблиці не було відповідних записів, інакше нічого не буде видалено.
Lexib0y

20

Оскільки це, мабуть, є простими стосунками батько / дитина між, petsі pets_activitiesвам буде краще створити обмеження зовнішнього ключа за допомогою каскаду видалення.

Таким чином, коли petsрядок видаляється, pets_activitiesрядки, пов’язані з нею, також автоматично видаляються.

Тоді ваш запит стає простим:

delete from `pets`
    where `order` > :order
      and `pet_id` = :pet_id

3
@Erick, якщо ви встановили референтну цілісність, каскадні видалення можуть спричинити не більше проблем, ніж видалення самостійно. Ми вже знаємо, що paце належна дитина pзавдяки id/pet_idкартографуванню.
paxdiablo

14
Ну, у вас, хлопці, є свої думки, але, здається, ви знижуєте багато сил СУБД. Каскадні делети - це стільки ж частина управління даними, скільки тригери, збережені процедури або обмеження, і вони небезпечні лише, якщо ви не знаєте, що ви робите. Але я не буду більше сперечатися з цим питанням, нам доведеться просто погодитися не погодитися.
paxdiablo

8
Ерік, зараз ти викликав мій інтерес. Як ви забезпечуєте цілісність даних всередині бази даних без обмежень?
paxdiablo

4
@Erick сказав: "Я також не використовую тригери, збережені процедури чи обмеження". Ах, ви використовуєте Excel. :-)
james.garriss

4
Я просто хочу продовжити це. Я змінив свою позицію щодо видалення каскадів у цій ситуації. Я був частиною нового середовища SQL, яке використовував їх, і добре їх використовував, і вони були дуже організовані. У цій системі дуже добре працювали на нашу користь, щоб ці каскади були на місці. Це, безумовно, заважало осиротілим даним і не було небезпечним. Проблема полягає в тому, що кожен, хто працює з базою даних, повинен розуміти, як безпечно ними користуватися. Але завжди є ризики, коли молодші розробники роблять зміни бази даних без нагляду.
Ерік Робертсон

14

Використовуй це

DELETE FROM `articles`, `comments` 
USING `articles`,`comments` 
WHERE `comments`.`article_id` = `articles`.`id` AND `articles`.`id` = 4

або

DELETE `articles`, `comments` 
FROM `articles`, `comments` 
WHERE `comments`.`article_id` = `articles`.`id` AND `articles`.`id` = 4

1
Знайшов хороший посібник для використання цього та кількох інших варіантів на mysqltutorial.org/mysql-delete-statement.aspx
Mavelo

3

На даний момент у мене немає бази даних mysql, на якій можна перевірити, але ви спробували вказати, що потрібно видалити до цього пункту? Наприклад:

DELETE p, pa FROM `pets` p,
        `pets_activities` pa
  WHERE p.`order` > :order
    AND p.`pet_id` = :pet_id
    AND pa.`id` = p.`pet_id`

Я думаю, що синтаксис, який ви використовували, обмежений новішими версіями mysql.


1
Цей запит виконано успішно, проте він не видалив жодних рядків (але я вважаю, що він мав би бути).
alex

2

Синтаксис мені здається правильним ... спробуйте змінити його на використання INNER JOIN...

Погляньте на це .


7
Шкода, що ви не включили власне рішення, оскільки посилання правильне!
mycroes

1

Для всіх, хто читав це у 2017 році, саме так я зробив щось подібне.

DELETE pets, pets_activities FROM pets inner join pets_activities
on pets_activities.id = pets.id WHERE pets.`order` > :order AND 
pets.`pet_id` = :pet_id

Як правило, для видалення рядків з кількох таблиць наведений нижче синтаксис, який я дотримуюсь. Рішення засноване на припущенні, що між двома таблицями існує деяке відношення.

DELETE table1, table2 FROM table1 inner join table2 on table2.id = table1.id
WHERE [conditions]

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