Получить рекурсивные родители в правильном порядке для удаления из таблицы MySQL
у меня есть структура таблицы, как это
mysql> SELECT id, name, parent_id FROM categories;
+-------+------------+-----------+
| id | name | parent_id |
+-------+------------+-----------+
| 15790 | Test | 0 |
| 15791 | Test2 | 0 |
| 16079 | Subtest | 15790 |
| 16080 | Subtest 2 | 15790 |
| 16081 | Subsubtest | 16079 |
+-------+------------+-----------+
теперь я хочу найти родителя для каждого ребенка и брата и брата и вернуть его в правильном порядке для удаления.
поэтому мой вывод в этом случае будет:
Array
(
16081,
16080,
16079,
15791,
15790
)
Я не могу удалить, просто изменив родительские идентификаторы, потому что это должно быть твердым возвращением дерева.
также я не могу / не могу изменить структуру таблицы. Так дом вроде индекса необходимый.
5 ответов
полагаю, у вас нет доступа к TRUNCATE
, SET
(Так что вы могли бы сделать SET FOREIGN_KEY_CHECKS=0;
),ALTER
, etc. так далее. и абсолютно должны использовать скрипт:
так как вопрос с тегами php
, это следует сделать трюк:
function reversetree($src_arr, $currentid = 0)
{
$cats = array();
foreach($src_arr as $id => $parent)
{
if($parent == $currentid)
{
$cats[] = $id;
$cats = array_merge($cats, reversetree($src_arr, $id));
}
}
return !$currentid ? array_reverse($cats) : $cats;
}
$rs = array();
foreach($pdo->query('SELECT id, parent_id FROM categories') as $row)
$rs[$row['id']] = $row['parent_id'];
$stmt = $pdo->prepare('DELETE FROM categories WHERE id = ?');
$pdo->beginTransaction();
foreach(reversetree($rs) as $v)
$stmt->execute(array($v));
$pdo->commit();
Я не понимаю, зачем нужны идентификаторы в определенном порядке. Вы можете удалить их с проводкой и все они будут удалены одновременно.
DELETE FROM categories WHERE ID IN (15790,15791,16079,16080,16081);
вы можете добавить ограничение внешнего ключа с каскадом при удалении. Внешний ключ будет указывать на ту же таблицу в поле родительского идентификатора.
когда вы удаляете родителя, все дети (независимо от того, какой уровень) удаляются автоматически.
<?php
// housekeeping
$pdo = new PDO($dsn, $user, $password);
$select = $pdo->prepare(
"SELECT parent.id AS parent_id, child.id AS child_id
FROM categories AS parent
JOIN categories AS child ON parent.id = child.parent_id
WHERE parent.id = ?"
);
$delete = $pdo->prepare('DELETE FROM categories WHERE id = ?');
// deletes $node_id, deletes its children first if required
function delete_node($node_id){
$select->execute( array($node_id) );
$children = $select->fetchAll(PDO::FETCH_NUM);
if (count($children) !== 0) { // if 0, then the category does not exist, or it has no child
foreach ($children as $child) { // call delete_node() recursively on each child
delete_node ($child[1]);
}
}
$delete->execute( array($node_id) ); // then delete this node (or do nothing if $node_id does not exist)
}
// to delete one category and all its sub-categories
delete_node(15790);
// to delete all contents
$allTopLevel = $pdo->exec('SELECT id FROM categories WHERE parent_id = 0')->fetchAll(PDO::FETCH_NUM);
foreach ($allTopLevel as $node) {
delete_node($node[0]);
}
не проверено, даже не уверен, что он "компилируется", но вы получаете идею. Обязательно заблокируйте таблицу (или запустите транзакцию) перед вызовом delete_node()
.
Извините,я не могу помочь, потому что SQL-это не мое. Но, возможно, кто-то может передать Java псевдо-код в решение
delete(table.getFirstRow().get(id));
delete(id_a){
for(data_set : table)
if(data_set.get(parent_id) == id_a)delete(data_set.get(id));
}
table.remove(id_a);
}
edit: нет итерации об элементах? Что-то вроде этого?
delete(list){
if(list.size() == 0)return;
idList = list.getAll(id);
plist = table.getAllWhichEquals(parent_id, idList);
delete(plist);
table.remove(idList);
}
ах, забудьте об этом, я удаляю не все одновременно, была просто попытка ^^