Как правильно удалять данные из многих таблиц?

#php #mysql #sql #database

#php #mysql #sql #База данных

Вопрос:

Когда вы хотите удалить категорию, сначала будут удалены все связанные продукты со связанными группами и атрибутами. Продукт имеет много связей.

Вот как это происходит при удалении категории:

 if (isset($_POST['catid']) amp;amp; $_POST['catid'] > 0) {

    $category_id = mysql_real_escape_string($_POST['catid']);

    $SQL = "SELECT * FROM products WHERE category_id = '$category_id'";
    $q_item = mysql_query($SQL);

    while ($dItem = mysql_fetch_assoc($q_item)) {
        $itemid = $dItem['id'];

        $SQL = "SELECT * FROM option_groups WHERE item_id = " . $itemid;
        $q = mysql_query($SQL);

        while ($option_group = mysql_fetch_assoc($q)) {
            $optionGroup = $option_group['id'];

            $SQL = "SELECT * FROM options WHERE option_group_id = " . $optionGroup;
            $q = mysql_query($SQL);
            while ($row = mysql_fetch_assoc($q)) {
                $option = $row['id'];
                mysql_query("DELETE FROM options WHERE id = " . $option);
                mysql_query("DELETE FROM e_groups_options WHERE option_id = " . $option);
            }

            mysql_query("DELETE FROM option_groups WHERE item_id = " . $itemid);
            mysql_query("DELETE FROM products WHERE id = " . $itemid);
        }
    }

    $SQL = "DELETE FROM categories WHERE id = '$category_id'";
    mysql_query($SQL);

}
  

Вы можете видеть, я использовал много запросов на удаление, и код выглядит немного запутанным, есть ли альтернативный способ и безопаснее?

Механизм хранения — MyISAM, и у меня более 100 000 строк данных в таблицах (поля индексируются).

Ответ №1:

Если бы эти таблицы были связаны с внешним ключом, вы могли бы указать ON DELETE CASCADE во внешнем ключе и просто удалить категорию. Вам придется переключиться на InnoDB, чтобы иметь возможность применить это. Цитирование документации по внешним ключам:

Для механизмов хранения, отличных от InnoDB, сервер MySQL анализирует синтаксис ВНЕШНЕГО КЛЮЧА в операторах CREATE TABLE, но не использует и не сохраняет его

Примите во внимание, что каскадные действия не запускают триггеры.

Вы можете переключить свои таблицы на InnoDB с ALTER TABLE table_name ENGINE = InnoDB помощью . Вы можете добавить внешний ключ с ALTER TABLE помощью инструкции, например:

 ALTER TABLE products
ADD FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE;
  

С помощью этого внешнего ключа всякий раз, когда вы выполняете DELETE оператор on categories , СУБД также удаляет products ссылку на эту категорию.

Комментарии:

1. Я не объявлял «ВНЕШНИЙ КЛЮЧ» в mysql.

2. @user791022 — хорошо, ты можешь? 🙂

3. Первый вопрос: используете ли вы MyISAM в качестве выбора или просто потому, что он используется по умолчанию? Если вы хотите, вы можете переключить свои таблицы на InnoDB с ALTER TABLE table_name ENGINE = InnoDB помощью ; . После этого вы можете создавать внешние ключи с помощью каскадирования.

Ответ №2:

Поскольку вы используете MyISAM и не можете выполнить каскадное удаление, вы можете просто выполнить объединенное удаление.

 DELETE table1, table2 FROM table1 LEFT JOIN table2 ON table1.id = table2.t1_id WHERE table1.id = $id
  

Ответ №3:

Я думаю, что лучший способ работать здесь — использовать механизм хранения, поддерживающий ограничения внешнего ключа (например, InnoDB), и позволить ему обрабатывать это с помощью КАСКАДА УДАЛЕНИЯ, чтобы СУБД выполнила всю работу за вас.

MyISAM пока не поддерживает внешние ключи.

Ответ №4:

Если вы не хотите или не можете изменить свой компонент database engine на innodb, вы можете выполнять удаления из нескольких таблиц с помощью join:

 DELETE t1, t2, t3
FROM tabel1 AS t1
LEFT JOIN table2 AS t2 ON t1.id = t2.pid
LEFT JOIN table3 AS t3 ON t2.id = t3.pid
WHERE t1.id = $id
  

Если есть способ объединить все таблицы, из которых вы хотите удалить строки, вы можете адаптировать свой код для выполнения одного запроса, подобного этому.

Ответ №5:

Ответ уже принят, но для интереса: если вы застряли в базе данных, которая не выполняет каскадные удаления, вы можете использовать ORM, такой как Propel. Я считаю, что это можно настроить для выполнения каскадных удалений вручную, если оно изначально не поддерживается БД.