6

私はこのようなテーブル構造を持っています

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
)

親IDを逆にするだけでは削除できません。これは、ツリーをしっかりと歩いて戻る必要があるためです。

また、テーブルの構造を変更することはできません/許可されていません。したがって、一種のインデックスを作成する必要があります。

4

5 に答える 5

6

TRUNCATESET(そうすることができますSET FOREIGN_KEY_CHECKS=0;)、ALTERなどへのアクセス権がなく、絶対にスクリプトを使用する必要があると仮定します。

質問はでタグ付けされているので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();
于 2012-06-26T05:25:47.230 に答える
3

特定の順序でIDが必要な理由がわかりません。トランザクションでそれらを削除することができ、それらはすべて同時に削除されます。

DELETE FROM categories WHERE ID IN (15790,15791,16079,16080,16081);
于 2012-06-26T00:36:31.943 に答える
1

DELETEでCASCADEを使用してFOREIGNKEY制約を追加できます。外部キーは、親IDフィールドの同じテーブルを指します。

親を削除すると、(レベルに関係なく)すべての子が自動的に削除されます。

于 2012-06-22T12:13:29.970 に答える
1
<?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()

于 2012-06-26T07:11:19.177 に答える
0

申し訳ありませんが、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);
}

編集:要素についての反復はありませんか?だからこのようなもの?

delete(list){
    if(list.size() == 0)return;
    idList = list.getAll(id);
    plist = table.getAllWhichEquals(parent_id, idList);
    delete(plist);
    table.remove(idList);
}

ああ、忘れてください、私は同時にすべてを削除しているわけではありません、ただの試みでした^^

于 2012-06-26T04:07:56.227 に答える