Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Рекурсивное удаление из базы данных
 
 автор: Ильдар   (16.08.2008 в 19:37)   письмо автору
 
 

имеется таблица разделов
поля:
id - порядковый номер раздела
parent - порядковый номер родительского раздела

нужно рекурсивно удалить все дочерние разделы удаляемого раздела.

Раздел -|- Раздел 1
        |- Раздел 2
        |- Раздел 3 -|- Раздел 4
                     |- Раздел 5 -|- раздел 7
                     |- Раздел 6

  Ответить  
 
 автор: Trianon   (16.08.2008 в 19:50)   письмо автору
 
   для: Ильдар   (16.08.2008 в 19:37)
 

Обязательно рекурсивно?
Вообще-то рекурсия здесь не нужна.

  Ответить  
 
 автор: Ильдар   (16.08.2008 в 19:57)   письмо автору
 
   для: Trianon   (16.08.2008 в 19:50)
 

А как можно удалить? Т.е. здесь же нужно удалить все разделы что пренадлежат разделу "раздел"

  Ответить  
 
 автор: Trianon   (16.08.2008 в 20:03)   письмо автору
 
   для: Ильдар   (16.08.2008 в 19:57)
 

И тем не менее.
Чисто из теории: рекурсия требуется при обходе дерева в глубину. При обходе в ширину рекурсия не нужна.
И если Вам неважно, в каком порядке отыскивать узлы - без рекурсии можно обойтись. Заодно сэкономите количество запросов к БД.

  Ответить  
 
 автор: Ильдар   (16.08.2008 в 20:04)   письмо автору
 
   для: Trianon   (16.08.2008 в 20:03)
 

Но здесь ведь у меня есть разделы и в ширину и в глубину!

  Ответить  
 
 автор: elrevin   (16.08.2008 в 21:06)   письмо автору
 
   для: Ильдар   (16.08.2008 в 19:37)
 

примерно так:

function DeleteFromBase($id)
{
  $QR=mysql_query("select * from your_table where parent=$id");
  while ($Row=mysql_fetch_array($QR))
  {
    DeleteFromBase($Row['id']);
  }
  mysql_query("delete from your_table where parent=$id");
}

  Ответить  
 
 автор: Trianon   (16.08.2008 в 21:17)   письмо автору
 
   для: elrevin   (16.08.2008 в 21:06)
 

Ну вот, кошмара чем-то подобного этому, я и ожидал. :)
Число SELECT * FROM и число DELETE FROM равно числу удаляемых узлов.

Неужели не найдется никого, кто напишет приемлемый вариант?

  Ответить  
 
 автор: elrevin   (16.08.2008 в 21:54)   письмо автору
 
   для: Trianon   (16.08.2008 в 21:17)
 

Если используемая СУБД-MySQL (и многие другие, которые не поддерживают рекурсивные запросы), то этого кошмара в данном случае не избежать.

  Ответить  
 
 автор: Trianon   (16.08.2008 в 22:15)   письмо автору
 
   для: elrevin   (16.08.2008 в 21:54)
 

>Если используемая СУБД-MySQL (и многие другие, которые не поддерживают рекурсивные запросы), то этого кошмара в данном случае не избежать.

Ничего, что BinLaden (16.08.2008 в 21:56) опроверг Ваше утверждение примером?

  Ответить  
 
 автор: elrevin   (16.08.2008 в 22:42)   письмо автору
 
   для: Trianon   (16.08.2008 в 22:15)
 

BinLaden предложил вариант где всеравно выполняется достаточно много запросов. Я уже признал что он лучше моего, но кошмар всеже остался и мое утверждение все еще в силе. Я только одного не понял, Вы роль судьи играете? Ваш вариант решения задачи?
Извиняюсь за оффтоп.

  Ответить  
 
 автор: BinLaden   (16.08.2008 в 23:21)   письмо автору
 
   для: elrevin   (16.08.2008 в 22:42)
 

Trianon тут самый опытный программист. Поэтому, IMHO, лучше сначала подумать, а потом уже пытаться с ним спорить :))

  Ответить  
 
 автор: Trianon   (16.08.2008 в 23:50)   письмо автору
 
   для: elrevin   (16.08.2008 в 22:42)
 

>BinLaden предложил вариант где всеравно выполняется достаточно много запросов.
>Я уже признал что он лучше моего, но кошмар всеже остался и мое утверждение все еще в силе.

Где ж остался, когда был убран? Кошмаром я вообще-то рекурсию называл. :)

>Я только одного не понял, Вы роль судьи играете?
Скорее я играю роль разрушителя заблуждений.


>Ваш вариант решения задачи?

<?
   $p 
",$id"
   do
   {
       
$p substr($p1);
       
$res mysql_query("SELECT id FROM tbl WHERE parent IN ($p)");
       
mysql_query("DELETE FROM  tbl WHERE parent IN ($p)");
       for(
$p ''$row mysql_fetch_assoc($res); $p .=",".$row['id']);
   } while(
$p);


Этот вариант по возможности экономит память. Число селектов и удалений в нем равно числу уровней в дереве.
Впрочем, если базу нельзя оставлять инконсистентной ни на секунду, то лучше применить вариант BinLaden (16.08.2008 в 22:25)

  Ответить  
 
 автор: Ильдар   (16.08.2008 в 21:22)   письмо автору
 
   для: elrevin   (16.08.2008 в 21:06)
 

может как то с помощью join?

  Ответить  
 
 автор: Ильдар   (16.08.2008 в 21:51)   письмо автору
 
   для: Ильдар   (16.08.2008 в 21:22)
 

хотя вариант elrevin мне нравится

  Ответить  
 
 автор: BinLaden   (16.08.2008 в 21:56)   письмо автору
 
   для: Ильдар   (16.08.2008 в 21:51)
 

Может быть как-то так?

<?php

$id_arr 
= array(1); // id раздела для удаления

while( list($key$id) = each($id_arr) )
{
    
$result mysql_query("SELECT `id` FROM `tbl` WHERE `parent` = {$id};");

    while( 
$row mysql_fetch_assoc($result) )
    {
        
$id_arr[] = $row['id'];
    }
}

mysql_query("DELETE FROM `tbl` WHERE `id` IN(" implode(', '$id_arr) . ");");

?>

  Ответить  
 
 автор: Trianon   (16.08.2008 в 22:08)   письмо автору
 
   для: BinLaden   (16.08.2008 в 21:56)
 

Направление выбрано верно. Но селектов всё еще слишком много....

  Ответить  
 
 автор: BinLaden   (16.08.2008 в 22:25)   письмо автору
 
   для: Trianon   (16.08.2008 в 22:08)
 

Может быть тогда так?

<?php 

$id_arr 
= array(1);
$trash = array();

while( !empty(
$id_arr) )

    
$trash array_merge($trash$id_arr);

    
$result mysql_query("SELECT `id` FROM `tbl` WHERE `parent` IN(" implode(', '$id_arr) . ");");

    for(
$id_arr = array(); $row mysql_fetch_assoc($result); $id_arr[] = $row['id']);
}

if( !empty(
$trash) )
{
    
mysql_query("DELETE FROM `tbl` WHERE `id` IN(" implode(', '$trash) . ");");
}

?>

  Ответить  
 
 автор: Trianon   (16.08.2008 в 23:02)   письмо автору
 
   для: BinLaden   (16.08.2008 в 21:56)
 

Вот теперь - нормально. Минимум селектов, один delete .

  Ответить  
 
 автор: elrevin   (16.08.2008 в 21:57)   письмо автору
 
   для: Ильдар   (16.08.2008 в 21:51)
 

можно сократить количество запросов DELETE:

function DeleteFromBase($id)
{
  $QR=mysql_query("select * from your_table where parent=$id");
  if (mysql_num_rows($QR)>0)
  {
    while ($Row=mysql_fetch_array($QR))
    {
      DeleteFromBase($Row['id']);
    }
    mysql_query("delete from your_table where parent=$id");
  }

  Ответить  
 
 автор: Trianon   (16.08.2008 в 22:11)   письмо автору
 
   для: elrevin   (16.08.2008 в 21:57)
 

>можно сократить количество запросов DELETE:
> mysql_query("delete from your_table where parent=$id");
Как было по запросу на узел - так и осталось.

  Ответить  
 
 автор: elrevin   (16.08.2008 в 22:18)   письмо автору
 
   для: Trianon   (16.08.2008 в 22:11)
 

:) Нет удаления несуществующих узлов.
BinLaden, предложил более лучший вариант.

  Ответить  
 
 автор: Ильдар   (17.08.2008 в 00:23)   письмо автору
 
   для: Ильдар   (16.08.2008 в 19:37)
 

Ооо! Спасибо вам всем за помощь и активное обсуждение темы))

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования