2009-05-19 71 views
15

我有一個包含分層數據的表。
保存其父項的Id(「ID」 - 鍵列)的列「ParentId」。刪除SQL表中的分層數據

當刪除一行時,我想刪除所有的子級(所有級別的嵌套)。

怎麼辦?

謝謝

回答

4

當行數不是太大時,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語句是爲了防止遞歸;如果你確定沒有,你可以把它放棄。

3

取決於您如何存儲您的層次結構。如果您只有ParentID,那麼它可能不是您採取的最有效的方法。爲了便於操縱子樹,你應該有一個附加列Parents是wouls存儲所有父ID,如:

/1/20/25/40 

這樣你就可以簡單地通過獲得所有子節點:

where Parents like @NodeParents + '%' 

第二種方法
而不僅僅是ParentID您可能也有leftright值。以這種方式插入會更慢,但選擇操作速度非常快。特別是隨着子樹節點打交道時... http://en.wikipedia.org/wiki/Tree_traversal

第三種方法
檢查遞歸CTE的,如果你使用SQL 2005+

第四種方法
如果使用SQL 2008,檢查HIERARCHYID型。它爲您的案例提供了足夠的可能性。 http://msdn.microsoft.com/en-us/magazine/cc794278.aspx

+0

NO,我不想整父母鏈存儲在列,因爲不斷有家長參與改變。並且很難跟蹤所有這些。 不能這樣做,因爲它是現在? – markiz 2009-05-19 12:16:27

+0

什麼是您的層次結構數據的主要操作?它是插入,更新還是讀取? – 2009-05-19 12:18:09

+0

我傾向於同意第一種方法 - 我們已經得到了我們正在做同樣事情的分層數據表。它有助於擺脫孩子,並且如果您需要對樹進行基於路徑的處理(例如,必須快速返回父母的所有孩子進行計算),這也會有所幫助。 我們最初嘗試使用觸發器來保持這一點,但真正發現添加大量數據時的性能影響是令人望而卻步的。 – 2009-05-19 13:05:18

2

添加觸發器表中這樣

創建mytable上進行刪除作爲 觸發TD_MyTable - 刪除的一個子級 從刪除d內刪除M於D.ID加入myTable的中號 = M.ID

每次刪除都會調用同一張表上的刪除,反覆調用觸發器。在線檢查書籍是否有其他規則。可能會限制觸發器可以嵌套的次數。

ST

+0

這些觸發器在SQL SERVER 2005 Express中可用? – markiz 2009-05-19 12:21:03

+0

但是我相信他們是你必須自己寫的。沒有嚮導。 – souLTower 2009-05-19 12:24:47

+0

我猜觸發器會工作,但觸發器的問題是,它將在每次刪除時被激活,即使在我只想刪除一行的情況下也是如此... – markiz 2009-05-19 13:22:30

0

取決於您的數據庫。如果您使用的是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,它變得有點棘手。正如其他人所說,觸發器或級聯刪除約束可能是最簡單的。

4

添加外鍵約束。下面的示例適用於MySQL的(syntax reference):

ALTER TABLE yourTable 
ADD CONSTRAINT makeUpAConstraintName 
FOREIGN KEY (ParentID) REFERENCES yourTable (ID) 
ON DELETE CASCADE; 

這將在數據庫級別上運行,數據庫管理系統將確保一旦行被刪除,所有引用行將被刪除了。

9

在SQL Server上:使用遞歸查詢。鑑於CREATE TABLE TMP(ID INT,家長INT),使用

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