私は階層データを持つテーブルを持っています。
親のId( "ID" - キー列)を保持する列 "ParentId"。SQLテーブル内の階層データの削除
行を削除するときに、すべての子(すべてのネスティングレベル)を削除したいとします。
どうすればよいですか?
ありがとうございました
私は階層データを持つテーブルを持っています。
親のId( "ID" - キー列)を保持する列 "ParentId"。SQLテーブル内の階層データの削除
行を削除するときに、すべての子(すべてのネスティングレベル)を削除したいとします。
どうすればよいですか?
ありがとうございました
行数がそれほど大きくない場合、erikkallenの再帰的アプローチが機能します。
は、ここですべての子供たちを収集するために一時テーブルを使用して代替です:
create table #nodes (id int primary key)
insert into #nodes (id) values (@delete_id)
while @@rowcount > 0
insert into #nodes
select distinct child.id
from table child
inner join #nodes parent on child.parentid = parent.id
where child.id not in (select id from #nodes)
delete
from table
where id in (select id from #nodes)
それは@delete_id持つ行で始まり、そこから下降します。 whereステートメントは再帰から保護することです。何もないと確信が持てば、あなたはそれを放棄することができます。
階層をどのように保存するかによって異なります。 ParentIDしか持っていない場合は、あなたが取った最も効果的なアプローチではないかもしれません。
where Parents like @NodeParents + '%'
:あなたは、単に、すべてのサブノードを取得することができます
/1/20/25/40
この方法:サブツリー操作を容易にするために、あなたは次のようにすべての親IDを格納しwouls追加の列Parents
を持つべきです2番目のアプローチ
ParentIDの代わりに、left
とright
という値を使用することもできます。この方法で挿入する挿入は遅くなりますが、選択操作は非常に高速です。
チェック再帰CTEのは、あなたがSQL 2008を使用している場合は、hierarchyid型の種類を確認あなたはSQL 2005+
第四のアプローチを使用している場合
...サブツリーノードでhttp://en.wikipedia.org/wiki/Tree_traversal
第三のアプローチを扱う場合は特に。それはあなたのケースに十分な可能性を与えます。 http://msdn.microsoft.com/en-us/magazine/cc794278.aspx
はNO、私は列全体の親チェーンを保存したくない、そこに一定の両親が関与して変化するので。そしてそれをすべて追跡するのは難しいでしょう。 今のところそれはできませんか? – markiz
階層データに対する主な操作は何ですか?それは挿入、更新、または読み込みですか? –
私は最初のアプローチに同意する傾向があります。同じことをしている階層的なデータの表があります。子を取り除くのに役立ちます。また、ツリーのパスベースの処理(計算のために親の子をすべて素早く返さなければならない場合など)が必要な場合にも役立ちます。 元々これを維持するためにトリガーを使用しようとしましたが、大量のデータを追加する際のパフォーマンスの影響は厳しいものでした。 –
として、削除のためにmytableは上のトリガーTD_MyTableを作成するには、この
のように表にトリガーを追加 - D.IDにmytableはM に参加削除Dの内側からMを削除する子ども の1つのレベルを削除します= M.ID
各削除は同じテーブルで削除を呼び出し、繰り返しトリガを呼び出します。追加ルールについては、オンラインで書籍をチェックしてください。トリガーがネストできる回数には制限があります。
ST
データベースによって異なります。 Oracleを使用している場合、あなたはこのような何かを行うことができます:
DELETE FROM Table WHERE ID IN (
SELECT ID FROM Table
START WITH ID = id_to_delete
CONNECT BY PRIOR.ID = ParentID
)
ETA:CONNECT BYなし
が、それは少しトリッキーを取得します。他の人が示唆しているように、トリガまたはカスケード削除の制約がおそらく最も簡単です。
MS SQL SERVER 2005 expressを使用しています – markiz
外部キー制約を追加します。次の例は、MySQL(syntax reference)の作品:
ALTER TABLE yourTable
ADD CONSTRAINT makeUpAConstraintName
FOREIGN KEY (ParentID) REFERENCES yourTable (ID)
ON DELETE CASCADE;
これはデータベースレベルで動作し、DBMSが一度行が削除されていることを確認し、すべての参照の行も削除されます。
自己参照カスケード削除はSQL Server 2005ではサポートされていません。「子」行の行を削除しようとするとエラーが発生します。 –
著者はこの回答を書いた時点でDBMSを指定していませんでした。私は参考のためにそれを残します。 – soulmerge
ああ、十分に公正です。明確化のためにありがとう。 –
SQL Serverの場合:再帰的なクエリを使用します。指定されたテーブルのTMP(同上int型、親int)をCREATE、あなたが望むもの
WITH x(Id) AS (
SELECT @Id
UNION ALL
SELECT tmp.Id
FROM tmp
JOIN x ON tmp.Parent = x.Id
)
DELETE tmp
FROM x
JOIN tmp ON tmp.Id = x.Id
トリガは唯一の32のレベルの深さ以下の階層のために使用することができます。
はいよりも優れていると私は本当に驚いています。最大レベルの深さは約8.9です。 とにかく、データベースで実行されるすべての削除コマンドでトリガーを有効にする必要はないので、トリガーを使用するつもりはないと思います。 – markiz
私はそれを試してみます – markiz
私はSQLであまり強くないです。だから私はこれを尋ねます: なぜ必要なのですか?「id = @delete_idのテーブルからIDを選択」 なぜ@delete_idを値として使うことができないのですか? – markiz
@markiz:良い点、私は答えを編集します! – Andomar