2

을 자체 조인 나는 대륙이 많은 도시이 많은 미국이 많은 지역이 많은 나라이 자체 조인 계층 테이블의 데이터가 있습니다.가 계층 구조를 평평하게 테이블

자기 결합 테이블 구조는 :

|-------------------------------------------------------------| 
| ID | Name   | Type  | ParentID | IsTopLevel | 
|-------------------------------------------------------------| 
| 1 | North America | Continent | NULL  | 1   | 
| 12 | United States | Country | 1   | 0   | 
| 113 | Midwest  | Region  | 12  | 0   | 
| 155 | Kansas  | State  | 113  | 0   | 
| 225 | Topeka  | City  | 155  | 0   | 
| 2 | South America | Continent | NULL  | 1   | 
| 22 | Argentina  | Country | 2   | 0   | 
| 223 | Southern  | Region  | 22  | 0   | 
| 255 | La Pampa  | State  | 223  | 0   | 
| 777 | Santa Rosa | City  | 255  | 0   | 
|-------------------------------------------------------------| 

나는 성공적 각 노드의 트리 구조와 깊이를 얻기 위해 재귀 CTE를 사용할 수 있었다. 내가 실패한 곳은 피벗을 사용하여 각 하위 위치와 그에 상응하는 각 수준의 멋진 목록을 만드는 것입니다.

예상 결과 :

|------------------------------------------------------------------------------------| 
| Continent  | Country  | Region | State | City  | Bottom_Level_ID | 
|------------------------------------------------------------------------------------| 
| North America | United States | Midwest | Kansas | Topeka  | 234    | 
| South America | Argentina  | Southern | La Pampa | Santa Rosa | 777    | 
|------------------------------------------------------------------------------------| 

내가 명확히해야 할 몇 가지 핵심 포인트가있다.

  1. 모든 단일 항목에는 하단 수준과 최상위 수준이 있습니다. 주어진 위치에 5 가지 유형이 모두 존재하지 않는 경우는 입니다. 나는이 데이터를 작성하는 경우이 표는 지구상의 모든 대륙에 대한 도시 수준에서 얼마나 엄청난 상상할 수

  2. 는, 나는 국가 수준에서 북미 50 개 항목이있을 것이다. 행 수십억 개

  3. 이유가 필요한 이유는 사람이 살았던 모든 주소의 역사적인 테이블에 가입하고 나무 위로 여행 할 수 있어야하기 때문입니다. 내가 그 테이블에서 LocationID를 가졌다 고 가정하면이 쿼리의 뷰에 조인을하고 해당 열을 넣을 수 있습니다.

  4. 이것은 2005 년 이전 데이터베이스이며 sysadmin이나 스키마를 제어하지 않습니다. 주로 유용한 형식으로

내 CTE 코드

--CTE 
;WITH Tree 
AS (
    SELECT ID, Name, ParentID, Type, 1 as Depth 
    FROM LocationTable 
    WHERE IsTopLevel = 1 
    UNION ALL 
    SELECT L.ID, L.Name, L.ParentID, L.Type, T.Depth+1 
    FROM Tree T 
    JOIN LocationTable L 
     ON L.ParentGUID = T.GUID 
) 

좋은 고체 데이터. 그러나 나는 그것에 대해 생각해보아야하고 이미이 형식의 테이블 구조가 아니므로 동시에 항목을 함께 사용하지 않으면 깊이 트리 검색을 수행하는 것이 왜 어려울까요?

어쨌든 여기 나머지 부분이 있습니다.

피벗 시도

;WITH Tree 
AS (
    SELECT ID, Name, ParentID, Type 
    FROM LocationTable 
    WHERE IsTopLevel = 1 
    UNION ALL 
    SELECT L.ID, L.Name, L.ParentID, L.Type 
    FROM Tree T 
    JOIN LocationTable L 
     ON L.ParentGUID = T.GUID 
) 
select * 
from Tree 
pivot (
    max(Name) 
    for Type in ([Continent],[Country],[Region],[State],[City]) 
) pvt 

그리고 지금은 다른 모든 것들에 대한 널 (null)와 열의 유형에 의하여 모든 것을 가지고있다. 이전에 어려움을 겪었으므로 필자의 피벗을 시도하기 전에 CTE 데이터를 필터링/조인해야하지만 어디서부터 시작해야할지 모르겠습니다. 내가 시도한 모든 것은 soooooooooo sloooooooow입니다.

CTE와 피벗을 이해할 때마다 새로운 점이 나를 극도로 냉담하게 만듭니다. 도와주세요.; ;

+0

가 5 열이있는 새로운 데이터 테이블에 훨씬을 쓸 수 있을까 * 사이드 바이 -측면*? 만약 당신이 올바르게 이해한다면, ** 항상 ** 5 가지 레벨이 있습니다. 트리의 유연성과 재귀 적 접근은 전혀 필요하지 않습니다. – Shnugo

+0

스키마를 변경할 수 없습니다. – BlueCucumber

답변

3

당신이 그것을 설명하지 않기 때문에 당신의 구조가 깨끗한 경우 (틈을, 5 단계는 항상) 당신은 쉬운 길을 갈 수 있습니다

이 데이터는 정말 고전 1 요구

: N-테이블 트리, 귀하의 국가, 주 등이 자신의 테이블에 거주하며 부모 기록에 연결되어있는 곳

ParentID 및 ID에 대한 색인이 있는지 확인하십시오!

DECLARE @tbl TABLE(ID INT,Name VARCHAR(100),Type VARCHAR(100),ParentID INT,IsTopLevel BIT); 
INSERT INTO @tbl VALUES 
(1,'North America','Continent',NULL,1) 
,(12,'United States','Country',1,0) 
,(113,'Midwest','Region',12,0) 
,(155,'Kansas','State',113,0) 
,(225,'Topeka','City',155,0) 
,(2,'South America','Continent',NULL,1) 
,(22,'Argentina','Country',2,0) 
,(223,'Southern','Region',22,0) 
,(255,'La Pampa','State',223,0) 
,(777,'Santa Rosa','City',255,0); 

SELECT Level1.Name AS Continent 
     ,Level2.Name AS Country 
     ,Level3.Name AS Region 
     ,Level4.Name AS State 
     ,Level5.Name AS City 
     ,Level5.ID AS Bottom_Level_ID 
FROM @tbl AS Level1 
    INNER JOIN @tbl AS Level2 ON Level1.ID=Level2.ParentID 
     INNER JOIN @tbl AS Level3 ON Level2.ID=Level3.ParentID 
      INNER JOIN @tbl AS Level4 ON Level3.ID=Level4.ParentID 
       INNER JOIN @tbl AS Level5 ON Level4.ID=Level5.ParentID 
WHERE Level1.ParentID IS NULL 

결과

Continent  Country   Region  State  City  Bottom_Level_ID 
North America United States Midwest  Kansas  Topeka  225 
South America Argentina  Southern La Pampa Santa Rosa 777 
+0

작은 샘플 세트에서 이것을 실행했는데 이런 식으로 할 수 없었습니다. 이 링크가 수십억 개의 관계 링크가 빠르다는 것을 알고 있습니까? 나는 내 DB에서 실행하기 시작했고, 여전히 계속 진행 중이다. – BlueCucumber

+0

수십억 개의 행이 꽤 많이 있습니다 ... ID 및 ParentID에 대한 색인이 있습니까? 내가 아는 한 위치를 주소에 바인딩해야합니다. 따라서 Bottom_Level_ID를 사용하여 전체 결과를 얻지 않아도됩니다. 옳은? 이것은 즉시 작동해야합니다 ... 어쨌든이 ** ** 숨겨진 RBAR입니다 어떤 재귀 적 접근보다 빠르다해야합니다 ... 하나의 좋은 선택이 될 수 있습니다 - 당신을 위해 작동한다면 - 내 쿼리를 사용하여) 'SELECT ... INTO NewTable FROM ...'을 사용하십시오. 이것은 몇 시간 만 실행될 수 있지만 한 번만 ... 인덱스를 배치하면 조명이 빠른 데이터 소스가됩니다. – Shnugo

0

CTE에 또 다른 해결책이 될 수 :

;WITH Tree 
AS (
    SELECT cast(NULL as varchar(100)) as C1, cast(NULL as varchar(100)) as C2, cast(NULL as varchar(100)) as C3, cast(NULL as varchar(100)) as C4, Name as C5, ID as B_Level 
    FROM LocationTable 
    WHERE IsTopLevel = 1 
    UNION ALL 
    SELECT T.C2, T.C3, T.C4, T.C5, L.Name, L.ID 
    FROM Tree T 
    JOIN LocationTable L 
     ON L.ParentID = T.B_Level 
) 
select * 
from Tree 
where C1 is not null 
+0

메시지 240, 레벨 16, 상태 1, 상태 1 유형이 앵커와 재귀 사이에서 일치하지 않습니다. 재귀 질의 "트리"의 "C4"열에 부분. – BlueCucumber

+0

네 말이 맞아. 나는 NULL을 cast (NULL은 varchar (100)로 대체)로 내 실수를 수정했습니다. 이제는 작품입니다. – Polux2

관련 문제