2009-05-19 5 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 문은 재귀로부터 보호합니다. 아무 것도 없다고 확신하는 경우, 그것을 버릴 수 있습니다.

+0

나는 그것을 시도 할 것입니다 – markiz

+0

나는 SQL에서 그렇게 강력하지 않습니다. 그래서 나는 다음과 같이 질문한다 : 왜 "id from @delete_id"테이블에서 id를 선택해야합니까? @delete_id를 값으로 사용할 수없는 이유는 무엇입니까? – markiz

+0

@markiz : 좋은 지적, 나는 대답을 편집 할 것이다! – Andomar

3

계층 구조를 저장하는 방법에 따라 다릅니다. ParentID 만 가지고 있다면 가장 효과적인 접근 방법이 아닐 수도 있습니다.

where Parents like @NodeParents + '%' 

: 당신은 단순히 모든 하위 노드를 얻을 수 있습니다

/1/20/25/40 

이 방법 : 하위 트리 조작의 용이성을 위해 당신은 같은 모든 상위 ID를 저장 wouls 추가 열 Parents을 가져야한다 두 번째 접근 방식
단지 ParentID 대신 leftright 값을 가질 수도 있습니다. 이 방법으로 삽입하는 것은 느리지 만 선택 작업은 매우 빠릅니다. 당신은 SQL 2008을 사용하는 경우 SQL에게 2005 +

네 번째 접근 방식
를 사용하는 경우 특히 http://en.wikipedia.org/wiki/Tree_traversal

세 번째 방법 ... 하위 트리 노드와
체크 재귀 열팽창 계수를 처리 할 때, HIERARCHYID 유형을 확인 . 그것은 당신의 사건에 대한 충분한 가능성을 제공합니다. http://msdn.microsoft.com/en-us/magazine/cc794278.aspx

+0

은 NO, 나는 열에서 전체 부모 체인을 저장하지 않습니다, 거기에 일정한 부모가 참여하고 변화하기 때문이다. 그리고 모든 것을 추적하는 것은 어려울 것입니다. 지금 당장은 할 수 없습니까? – markiz

+0

계층 구조 데이터에 대한 기본 작업은 무엇입니까? 삽입, 업데이트 또는 읽기입니까? –

+0

나는 첫 번째 접근법에 동의하는 경향이 있습니다. 우리는 같은 일을하는 계층 적 데이터의 테이블을 가지고 있습니다. 자녀를 없애는 데 도움이되며 트리의 경로 기반 처리 (예 : 계산을 위해 부모의 모든 하위 항목을 빠르게 반환해야하는 경우)를 수행해야하는 경우에도 도움이됩니다. 원래이 기능을 유지하기 위해 트리거를 사용해 보았지만 대용량 데이터를 추가 할 때 성능에 미치는 영향은 매우 컸습니다. –

2

가 삭제 등을위한 myTable에에 트리거 TD_MyTable을 만들이

같은 테이블에 트리거를 추가 - 아이들의 한 단계를 삭제 D.ID에 myTable에 M 가입 삭제 D 내부에서 M을 삭제 = M.ID

각 삭제는 동일한 테이블에서 반복적으로 트리거를 호출하여 삭제를 호출합니다. 추가 규칙은 온라인에서 책을 확인하십시오. 트리거가 중첩 될 수있는 횟수에는 제한이있을 수 있습니다.

ST

+0

SQL SERVER 2005 Express에서 이러한 트리거를 사용할 수 있습니까? – markiz

+0

그러나 나는 당신이 그들 자신을 속달로 써야한다고 믿습니다. 그것을위한 마법사가 없습니다. – souLTower

+0

나는 방아쇠가 작동하지만 방아쇠의 문제는 모든 삭제마다 하나의 행만 삭제하려고 할 때도 활성화된다는 것입니다 ... – markiz

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없이

, 그것은 조금 난이도가 도착합니다. 다른 사람들이 제안했듯이, 트리거 또는 계단식 삭제 제한이 아마도 가장 쉽습니다.

+0

MS SQL SERVER 2005 express – markiz

4

외래 키 제약 조건을 추가하십시오. 다음 예제는 MySQL은 (syntax reference) 작동 :

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

이 데이터베이스 수준에서 작동, DBMS의이 행이 너무 모든 참조 행이 삭제됩니다 삭제되면 다음 사항을 확인합니다.

+0

자기 참조 계단식 삭제는 SQL Server 2005에서 지원되지 않습니다. "자식"행이있는 행을 삭제하려고하면 오류가 발생합니다. –

+0

필자는이 답변을 작성한 시점에서 DBMS를 지정하지 않았습니다. 나는 그것을 참조로 남겨 둘 것이다. – soulmerge

+0

아, 그 정도면 충분합니다. 명확히 해 주셔서 감사합니다. –

9

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 
0

당신이 원하는 것은 이러한 테이블 사이 referential integrity이다 사용을 감안할 때.

+0

테이블 만 있습니다 ... – markiz

0

트리거는 32 레벨 깊은 이하의 계층 구조에 사용할 수 있습니다

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/05/11/defensive-database-programming-fun-with-triggers.aspx

+0

예보다 성능이 우수하다면 정말 놀랍습니다. 최대 레벨 깊이는 약 8,9입니다. 어쨌든 데이터베이스에서 실행되는 모든 삭제 명령에서 트리거를 활성화 할 필요가 없기 때문에 트리거를 사용하지 않을 것이라고 생각합니다. – markiz