#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. Я считаю, что это можно настроить для выполнения каскадных удалений вручную, если оно изначально не поддерживается БД.