부모-자식 트리 계층 적 순서


21

SQL Server 2008 R2의 데이터를 따라야합니다. SQLFiddle

개요:

테이블 생성 [dbo]. [ICFilters] (
   [ICFilterID] [int] IDENTITY (1,1) NOT NULL,
   [ParentID] [int] NOT NULL DEFAULT 0,
   [FilterDesc] [varchar] (50) NOT NULL,
   [활성] [tinyint] NOT NULL DEFAULT 1,
 제약 조건 [PK_ICFilters] 기본 키 클러스터 
 ([ICFilterID] ASC) 포함 
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    IGNORE_DUP_KEY = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON
 ) ON [PRIMARY]
) ON [PRIMARY]

[dbo]에 삽입. [ICFilters] (ParentID, FilterDesc, Active)
가치 
(0, '제품 유형', 1),
(1, 'ProdSubType_1', 1),
(1, 'ProdSubType_2', 1),
(1, 'ProdSubType_3', 1),
(1, 'ProdSubType_4', 1),
(2, 'PST_1.1', 1),
(2, 'PST_1.2', 1),
(2, 'PST_1.3', 1),
(2, 'PST_1.4', 1),
(2, 'PST_1.5', 1),
(2, 'PST_1.6', 1),
(2, 'PST_1.7', 0),
(3, 'PST_2.1', 1),
(3, 'PST_2.2', 0),
(3, 'PST_2.3', 1),
(3, 'PST_2.4', 1),
(14, 'PST_2.2.1', 1),
(14, 'PST_2.2.2', 1),
(14, 'PST_2.2.3', 1),
(3, 'PST_2.8', 1)

표:

| ICFILTERID | 부모님 | 필터 데스크 | 활성 |
--------------------------------------------------
| 1 | 0 | 제품 유형 | 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 3 | 1 | ProdSubType_2 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 20 | 3 | PST_2.8 | 1 |

모든 행에는 부모의 ID와 루트의 ID가 parentid = 0있습니다. 의 FilterDesc샘플 설명이므로 주문을 위해 구문 분석을 시도 할 수 없습니다.

질문

트리와 같은 방식으로 모든 행을 선택할 수 있습니까? 그렇다면 어떻게? 'tree-like'라고 말할 때 부모를 반복적으로 선택하고 모든 자식과 그 자식의 모든 자식을 차례로 선택합니다. 깊이 첫 나무 순회.

내 친구와 나는 노력했지만 해결책이 부족했지만 계속 노력할 것입니다. 나는 SQL에 상당히 익숙하지 않으므로 아마도 쉽게 수행 할 수 있으며 필요한 것보다 더 힘들게 만들고 있습니다.

예 (원하는) 출력 :

| ICFILTERID | 부모님 | 필터 데스크 | 활성 |
--------------------------------------------------
| 1 | 0 | 제품 유형 | 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 3 | 1 | ProdSubType_2 | 1 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 20 | 3 | PST_2.8 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |

CTE를 사용하는 것이 가장 좋습니다
Kin Shah

1
다음은 테이블 데이터를 특정 순서로로드하지 않고도 원하는 결과 정렬을 보여주는 스레드입니다. row_number ()와 partition by를 사용하여 원하는 정렬을 가능하게하는 "경로"를 만듭니다. ask.sqlservercentral.com/questions/48518/…

답변:


25

자, 충분한 뇌 세포가 죽었습니다.

SQL 바이올린

WITH cte AS
(
  SELECT 
    [ICFilterID], 
    [ParentID],
    [FilterDesc],
    [Active],
    CAST(0 AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters]
  WHERE [ParentID] = 0
  UNION ALL
  SELECT 
    i.[ICFilterID], 
    i.[ParentID],
    i.[FilterDesc],
    i.[Active],  
    Level + CAST(i.[ICFilterID] AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters] i
  INNER JOIN cte c
    ON c.[ICFilterID] = i.[ParentID]
)

SELECT 
  [ICFilterID], 
  [ParentID],
  [FilterDesc],
  [Active]
FROM cte
ORDER BY [Level];

2
이것이 바로 내가 필요한 것입니다! 나는 너무 많은 뇌 세포가 이것으로 죽었다는 데 동의합니다. 내가 원하는 것을 명확하지 않았습니까? 그렇다면 나중에 참조 할 수 있도록 질문을 편집하겠습니다. 나는 그것이 필요한 것보다 확실히 어렵게 만들었습니다 ...
Archangel33

1
@ Archangel33 당신은 문제와 필요한 것을 세우는 일을 잘했습니다. 또한 sqlfiddle은 실제로 도움이됩니다.
트래비스

2
+1 만 그 아이템은 정확한 순서로 삽입되지만, 정렬을위한 다른 필드 OT 아직 구현되지 않는 작동 정렬 [ICFilterID [INT] IDENTITY (1,1)를 사용하여
bummi

4
나는 이것이 100 % 올바른 해결책이라고 믿지 않습니다. 계층 구조에서 모든 행을 올바른 레벨로 나열하기는 어렵지만 질문이 요청한 순서대로 나열하지는 않습니다. 질문에 따라 행을 올바른 순서로 나열 할 수 있습니까? 그것은 내가 찾고있는 것입니다.

1
제공된 [FilterDesc]열의 데이터 가 가상이고 순서가 불필요하거나 중요하지 않기 때문에 내 질문에 대답합니다 . @Travis Gan의 답변에 나온 논리에 따라이 순서를 얻기 위해해야하는 모든 것은에 다른 CAST것을 추가 하는 것 Level입니다. 예. Level + CAST( CAST(i.[ICFilterID] AS varbinary(max)) AS Level가된다 Level + CAST(i.[FilterDesc] AS varbinary(max)) + CAST(i.[ICFilterID] AS varbinary(max)) AS Level.
Archangel33

1

위의 내용이 제대로 작동하지 않는 것 같습니다. 페이스 북 유형의 데이터로 2 테이블 설정을 상상해보십시오. 표 1에는 PostId + 기타 필드가 있습니다. PostId는 자동으로 증가하며 인터페이스에서 분명히 최신 게시물이 맨 위에 오도록 DESC를 정렬합니다.

이제 의견 표에 대해. 표 2이 테이블 CommentId는 기본 키, 자동 번호입니다. GUI에서 ASC를 표시하여 스레드를 읽을 때 의미가 있습니다. (맨 위의 가장 오래된 (작은 숫자)) 표 2의 다른 중요한 키는 PostId (FK back to posts) 및 ParentId (FK to CommentId)입니다. 여기서 Post의 "루트"주석 인 경우 ParentId는 NULL입니다. 누군가가 댓글에 답장하면 parentId가 댓글 ID로 채워집니다.
당신이 드리프트를 얻을 바랍니다. CTE는 다음과 같습니다.

WITH  Comments
        AS ( SELECT  CommentId , ParentId, CAST(CommentId AS VARBINARY(MAX)) AS Sortkey, 0 AS Indent
             FROM    dbo.Comments
             WHERE   ParentId IS NULL AND PostId = 105
             UNION ALL
             SELECT  b.CommentId , b.ParentId,  c.Sortkey + CAST(b.CommentId AS varbinary(max))  AS Sortkey, c.Indent + 1 AS Indent
             FROM    dbo.Comments b
             INNER JOIN Comments c ON c.CommentId = b.ParentId
           )
   SELECT   *
   FROM     Comments
   ORDER BY Sortkey

샘플 출력

1   NULL    0x0000000000000001  0
5   1   0x00000000000000010000000000000001  1
6   5   0x000000000000000100000000000000010000000000000005  2
2   NULL    0x0000000000000002  0

105 번 F / B 게시물에 2 개의 댓글 (댓글 1과 2)이있었습니다. 누군가 Comment1 (댓글 5, ParentId 1)에 댓글을 달고 다른 사람이 댓글에 댓글을 달았습니다. Comment5 (CommentId 6, ParentId 6)

그리고 비올라, 순서가 정확하고 게시물 아래에서 이제 올바른 순서로 주석을 표시 할 수 있습니다. 페이스 북과 같이 게시물을 들여 쓰기 위해 (수준이 깊을수록 왼쪽에서 더 많이 마진해야 함), 들여 쓰기라는 열이 있습니다. 루트는 0이고 합집합에는 c.Indent + 1 AS 들여 쓰기 코드가 있습니다. 이제 들여 쓰기에 32px로 가정하고 주석을 멋진 계층 구조와 개요로 표시 할 수 있습니다.

정렬 키를 +1로 시드하는 데이터베이스 관리 키를 엉망보다 엉망으로 변경하는 것이 더 좋기 때문에 자동 증가 기본 키 CommentId를 SortKey 작성의 원동력으로 사용하는 데 아무런 문제가 없습니다.


0
create table pc ( parent varchar(10), child varchar(10) )

insert into pc values('a','b');
insert into pc values('a','c');
insert into pc values('b','e');
insert into pc values('b','f');
insert into pc values('a','d');
Insert into pc values('b','g');
insert into pc values('c','h');
insert into pc values('c','i');
insert into pc values('d','j');
insert into pc values('f','k');
insert into pc values('x','y');
insert into pc values('y','z');
insert into pc values('m','n');

 DECLARE @parent varchar(10) = 'a';
 WITH cte AS
 (
  select null parent, @parent child, 0 as level
   union
  SELECT  a.parent, a.child , 1 as level
    FROM pc a
   WHERE a.parent = @parent
   UNION ALL
  SELECT a.parent, a.child , c.level +    1
  FROM pc a JOIN cte c ON a.parent = c.child
  )
  SELECT distinct parent, child , level
  FROM cte
  order by level, parent

이것은 모든 자손과 수준을 줄 것입니다.
희망이 있습니다 :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.