0

テーブルが再帰的にそれ自体を指す特定のレコード ID から子孫レコードを削除するための戦略は何ですか? 具体的には、PDO、PHP、および MySQL 5.0 以降を使用しています。

次の列を持つカテゴリ テーブルを想像してください。

  • ID
  • 親ID
  • 種別名

ID が 0 の場合、それはルート カテゴリです。その id は主キーではありません。覚えておいてください。多くのルート カテゴリが存在する可能性があります。

Food と Shelter のルート カテゴリのように、複数の階層があり、それらの子、それらの子などがあると想像してください。これらは子孫です。たとえば、誰かが野菜を削除した場合、食品と避難所はルート カテゴリとして残されますが、豆と同様にニンジンも削除されます。マンションとキャビンも別のツリーからのものであるため、取り残されます。それを得る?

EDIT:私の悪い - 列を忘れてしまった - parent_id。これは非常に重要です。

4

3 に答える 3

2

おそらくシナリオではオプションではありませんが、階層データを格納するためのネストされたセットモデルにより、説明したような操作が非常に効率的になります。

また、次の記事も役立つ場合があります。

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

于 2011-12-16T21:29:47.783 に答える
1

単純なカスケード参照整合性がそれを行う必要があります-ONDELETECASCADEを使用して外部キーを宣言します。また、インデックスを作成する場合はparent_id、かなり効率的である必要があります(これは、とにかくMySQLで必要とされるようです。他のDBMSでは、通常、インデックスのないFKが許可されます)。

例えば:

CREATE TABLE your_table (
    id int PRIMARY KEY,
    parent_id int DEFAULT NULL,
    category_name varchar(45) NOT NULL,
    -- Will also create index on parent_id:
    CONSTRAINT your_table_fk1 FOREIGN KEY (parent_id) REFERENCES your_table (id)
        ON DELETE CASCADE
);

INSERT INTO your_table (id, category_name) VALUES (1, 'Food');
INSERT INTO your_table (id, category_name) VALUES (2, 'Shelter');
INSERT INTO your_table (id, parent_id, category_name) VALUES (3, 1, 'Vegetables');
INSERT INTO your_table (id, parent_id, category_name) VALUES (4, 3, 'Carrots');
INSERT INTO your_table (id, parent_id, category_name) VALUES (5, 3, 'Beans');
INSERT INTO your_table (id, parent_id, category_name) VALUES (7, 2, 'Mansions');
INSERT INTO your_table (id, parent_id, category_name) VALUES (8, 2, 'Cabins');

次に、実行すると...

DELETE FROM your_table WHERE category_name = 'Vegetables'

...「野菜」だけでなく、「にんじん」と「豆」も削除されます。

これは再帰的にも機能するので...

DELETE FROM your_table WHERE category_name = 'Food'

...最初のレベルで「食品」、2番目のレベルで「野菜」、3番目のレベルで「ニンジン」と「豆」を削除します。

于 2011-12-18T05:11:16.133 に答える
0

ネストされたセット モデルはより強力ですが、再帰を使用した次の例で十分な場合もあります。

public function deleteCategory($sCatID) {
  if (empty($sCatID)) {
    return FALSE;
  }
  // you can get your PDO database connection your own way -- this is my way for my framework
  $PDO = $this->data->mysql();
  // recursively find all the descendents of this category and delete those too
  $sSQL = "
  SELECT
    `id`
  FROM
    `categories`
  WHERE
    `parent_id` = :parent_id;
  ";
  $st = $PDO->prepare($sSQL);
  $st->bindValue(':parent_id',$sCatID);
  try {
    $st->execute();
    $rsRows = $st->fetchAll();
    foreach($rsRows as $rwRow) {
      $sChildCatID = $rwRow['id'];
      // note the recursion here!
      $this->deleteCategory($sChildCatID);
    }
  } catch (PDOException $e) {}
  unset($st);
  // now delete this category
  $sSQL = "
  DELETE FROM
    `categories`
  WHERE
    `id` = :id
  LIMIT 1;
  ";
  $st = $PDO->prepare($sSQL);
  $st->bindValue(':id',$sCatID);
  try {
    $st->execute();
  } catch (PDOException $e){}
}
于 2011-12-16T21:57:38.643 に答える