Oracle 트 리 작업 (select... start with... connect by... prior)

Oacle 트 리 조회 의 가장 중요 한 것 은 select. start with.. connect by.. prior 문법 입 니 다.이 문법 을 바탕 으로 우 리 는 하나의 표 형 구 조 를 나무의 순서 로 배열 할 수 있다.다음은 Oacle 에서 트 리 조회 에 자주 사용 되 는 조회 방식 과 트 리 조회 와 관련 된 Oacle 특성 함수 등 을 설명 합 니 다. 여기 서 는 한 장의 표 에 있 는 트 리 조회 방식 만 언급 되 고 여러 표 의 관련 이 없습니다.
1. 테스트 테이블 과 테스트 데이터 준비
--       
create table tb_menu(
   id     number(10) not null, --  id
   title  varchar2(50), --  
   parent number(10) --parent id
)
 
--   
insert into tb_menu(id, title, parent) values(1, '   1',null);
insert into tb_menu(id, title, parent) values(2, '   2',null);
insert into tb_menu(id, title, parent) values(3, '   3',null);
insert into tb_menu(id, title, parent) values(4, '   4',null);
insert into tb_menu(id, title, parent) values(5, '   5',null);
--    
insert into tb_menu(id, title, parent) values(6, '    6',1);
insert into tb_menu(id, title, parent) values(7, '    7',1);
insert into tb_menu(id, title, parent) values(8, '    8',1);
insert into tb_menu(id, title, parent) values(9, '    9',2);
insert into tb_menu(id, title, parent) values(10, '    10',2);
insert into tb_menu(id, title, parent) values(11, '    11',2);
insert into tb_menu(id, title, parent) values(12, '    12',3);
insert into tb_menu(id, title, parent) values(13, '    13',3);
insert into tb_menu(id, title, parent) values(14, '    14',3);
insert into tb_menu(id, title, parent) values(15, '    15',4);
insert into tb_menu(id, title, parent) values(16, '    16',4);
insert into tb_menu(id, title, parent) values(17, '    17',4);
insert into tb_menu(id, title, parent) values(18, '    18',5);
insert into tb_menu(id, title, parent) values(19, '    19',5);
insert into tb_menu(id, title, parent) values(20, '    20',5);
--    
insert into tb_menu(id, title, parent) values(21, '    21',6);
insert into tb_menu(id, title, parent) values(22, '    22',6);
insert into tb_menu(id, title, parent) values(23, '    23',7);
insert into tb_menu(id, title, parent) values(24, '    24',7);
insert into tb_menu(id, title, parent) values(25, '    25',8);
insert into tb_menu(id, title, parent) values(26, '    26',9);
insert into tb_menu(id, title, parent) values(27, '    27',10);
insert into tb_menu(id, title, parent) values(28, '    28',11);
insert into tb_menu(id, title, parent) values(29, '    29',12);
insert into tb_menu(id, title, parent) values(30, '    30',13);
insert into tb_menu(id, title, parent) values(31, '    31',14);
insert into tb_menu(id, title, parent) values(32, '    32',15);
insert into tb_menu(id, title, parent) values(33, '    33',16);
insert into tb_menu(id, title, parent) values(34, '    34',17);
insert into tb_menu(id, title, parent) values(35, '    35',18);
insert into tb_menu(id, title, parent) values(36, '    36',19);
insert into tb_menu(id, title, parent) values(37, '    37',20);
--    
insert into tb_menu(id, title, parent) values(38, '    38',21);
insert into tb_menu(id, title, parent) values(39, '    39',22);
insert into tb_menu(id, title, parent) values(40, '    40',23);
insert into tb_menu(id, title, parent) values(41, '    41',24);
insert into tb_menu(id, title, parent) values(42, '    42',25);
insert into tb_menu(id, title, parent) values(43, '    43',26);
insert into tb_menu(id, title, parent) values(44, '    44',27);
insert into tb_menu(id, title, parent) values(45, '    45',28);
insert into tb_menu(id, title, parent) values(46, '    46',28);
insert into tb_menu(id, title, parent) values(47, '    47',29);
insert into tb_menu(id, title, parent) values(48, '    48',30);
insert into tb_menu(id, title, parent) values(49, '    49',31);
insert into tb_menu(id, title, parent) values(50, '    50',31);
commit;
 
select * from tb_menu;
parent 필드 는 상위 id 를 저장 합 니 다. 최상 위 부모 노드 라면 이 parent 는 null (한 마디 보충 해 야 합 니 다. 처음에 이렇게 디자인 했 지만 지금 은 표 에 null 기록 이 있 는 것 이 좋 습 니 다. 이것 은 전체 텍스트 스 캔 을 일 으 킬 수 있 습 니 다. 0 으로 바 꾸 는 것 을 권장 합 니 다).
2. 나무 조작 우 리 는 가장 기본 적 인 조작 에서 나무 조회 에서 흔히 볼 수 있 는 조작 을 점차적으로 열거 하고 모든 조회 한 노드 는 가족 중의 세대 로 예 를 들 면.1) 트 리 의 모든 최상 위 부모 노드 (세대 가 가장 긴 사람) 를 찾 습 니 다.이 트 리 가 디 렉 터 리 구조 라 고 가정 하면 첫 번 째 작업 은 항상 모든 최상 위 노드 를 찾 은 다음 에 이 노드 에 따라 부하 노드 를 찾 습 니 다.
select * from tb_menu m where m.parent is null;
2) 한 노드 의 직속 하위 노드 (모든 아들) 를 찾 습 니 다.직속 하위 노드 를 찾 았 다 면 트 리 로 조회 하지 않 아 도 됩 니 다.
select * from tb_menu m where m.parent=1;

3), 한 노드 의 모든 직속 하위 노드 (모든 후대) 를 찾 습 니 다.
select * from tb_menu m start with m.id=1 connect by m.parent=prior m.id;

이것 은 id 가 1 인 노드 아래 의 모든 직속 하위 노드 를 찾 습 니 다. 하위 클래스 와 손자 세대 의 모든 직속 노드 를 포함 합 니 다.
4) 、 한 노드 의 직속 부모 노드 (아버지) 를 찾 습 니 다.노드 의 직속 부모 노드 를 찾 았 다 면 트 리 로 조회 하지 않 아 도 됩 니 다.
select c.id, c.title, p.id parent_id, p.title parent_title
from tb_menu c, tb_menu p
where c.parent=p.id and c.id=6;
5) 한 노드 의 모든 직속 부 노드 (조상) 를 찾 습 니 다.
select * from tb_menu m start with m.id=38 connect by prior m.parent=m.id;
여기 서 찾 은 것 은 id 가 1 인 모든 직속 부모 노드 이다. 예 를 들 어 한 사람의 아버지, 할아버지 등 을 찾 는 것 이다.그러나 주의해 야 할 것 은 이 조회 결과 의 순 서 는 먼저 하위 노드 를 열거 한 다음 에 부모 노드 를 열거 하 는 것 이 고 우선 역순 이 라 고 생각 하 는 것 이다.
위 에 두 개의 트 리 조회 방식, 세 번 째 문장 과 다섯 번 째 문장 이 열거 되 어 있 는데 이 두 문장 사이 의 차 이 는 prior 키워드 의 위치 가 다 르 기 때문에 조회 방식 이 다르다 는 것 을 결정 했다.parent = prior id 일 때 데이터 베 이 스 는 현재 id 에 따라 parent 와 이 id 가 같은 기록 을 교체 하기 때문에 조회 결 과 는 모든 하위 기록 을 교체 한 것 입 니 다.한편, prior parent = id 일 때 데이터 베 이 스 는 현재 parent 에 따라 현재 parent 와 같은 id 의 기록 을 교체 하기 때문에 조회 한 결 과 는 모든 부모 류 결과 입 니 다.
다음은 일련의 나무 구 조 를 대상 으로 하 는 더욱 깊 은 차원 의 조회 이다. 이곳 의 조 회 는 반드시 가장 좋 은 조회 방식 이 아니 라 그 중의 한 가지 실현 일 수도 있다.
6), 한 노드 의 형제 노드 (친형제) 를 조회 합 니 다.
select * from tb_menu m
where exists (select * from tb_menu m2 where m.parent=m2.parent and m2.id=6)
7) 한 노드 와 같은 등급 의 노드 (족 형제) 를 조회 합 니 다.표 에 등급 필드 를 설정 하면 이러한 조 회 를 할 때 매우 쉬 울 것 입 니 다. 같은 등급 은 그 노드 와 같은 등급 입 니 다. 이 필드 를 사용 하지 않 을 때의 실현 을 보 여 줍 니 다!
with tmp as(
      select a.*, level leaf        
      from tb_menu a                
      start with a.parent is null     
      connect by a.parent = prior a.id)
select *                               
from tmp                             
where leaf = (select leaf from tmp where id = 50);
여기 서 두 가지 기 교 를 사용 합 니 다. 하 나 는 level 을 사용 하여 모든 노드 가 표 에 있 는 등급 을 표시 하 는 것 입 니 다. 그리고 with 문법 으로 등급 이 있 는 임시 표를 모 의 한 것 입 니 다.
8) 한 노드 의 부모 노드 의 형제 노드 (큰아버지 와 숙부) 를 조회 합 니 다.
with tmp as(
    select tb_menu.*, level lev
    from tb_menu
    start with parent is null
    connect by parent = prior id)

select b.*
from tmp b,(select *
            from tmp
            where id = 21 and lev = 2) a
where b.lev = 1
union all
select *
from tmp
where parent = (select distinct x.id
                from tmp x, --  
                     tmp y, --  
                     (select *
                      from tmp
                      where id = 21 and lev > 2) z --  
                where y.id = z.parent and x.id = y.parent); 

이곳 조 회 는 다음 과 같은 몇 단계 로 나 뉜 다.
우선 7 번 째 와 마찬가지 로 모든 시 계 를 임시 표 에 등급 을 더 합 니 다.
그 다음으로 등급 에 따라 몇 가지 유형 이 있 는 지 판단 한다. 상기 글 에서 예 를 들 면 세 가지 상황 이 있다.
(1) 현재 노드 는 최고급 노드, 즉 조 회 된 lev 값 이 1 이면 상급 노드 가 없고 고려 하지 않 습 니 다.
(2) 현재 노드 는 2 급 노드 이 고 조회 한 lev 값 은 2 이 므 로 lev 등급 이 1 인 것 이 바로 상급 노드 의 형제 노드 이다.
(3) 다른 상황 은 3 과 이상 의 등급 이다. 그러면 상사 의 상급 노드 (할아버지) 를 조회 한 다음 에 할아버지 의 하급 노드 가 모두 이 노드 에 속 하 는 상급 노드 의 형제 노드 라 고 판단 해 야 한다.
마지막 으로 유 니 온 을 이용 해 조회 한 결 과 를 결합 해 결과 집 을 만 드 는 것 이다.
9) 한 노드 의 부모 노드 의 동급 노드 (족 숙) 를 조회 합 니 다.
이것 은 사실 일곱 번 째 상황 과 같다.
with tmp as(
      select a.*, level leaf        
      from tb_menu a                
      start with a.parent is null     
      connect by a.parent = prior a.id)
select *                               
from tmp                             
where leaf = (select leaf from tmp where id = 6) - 1;
기본적으로 흔히 볼 수 있 는 조회 가 안에 있 고 흔 하지 않 은 것 도 일부 있다.그 중에서 조회 의 내용 은 모두 노드 의 기본 정보 이 고 모두 데이터 시트 의 기본 필드 이지 만 트 리 조회 에서 특별한 수요 가 있 고 조회 데 이 터 를 처리 한 것 으로 흔히 볼 수 있 는 것 은 트 리 경로 등 을 포함한다.
하나의 개념 을 보충 하면 데이터 베이스 에 있어 뿌리 노드 는 반드시 데이터 베이스 에서 디자인 한 최고급 노드 가 아니 라 데이터 베이스 에 있어 뿌리 노드 는 start with 가 시작 하 는 곳 이다.아래 열거 한 것 은 나무 와 관련 된 특수 한 요구 사항 이다.
10) 이름 은 이름 의 모든 경 로 를 표시 해 야 합 니 다.여기 서 흔히 볼 수 있 는 두 가지 상황 이 있 습 니 다. 하 나 는 현재 노드 의 이름 (또는 다른 속성) 까지 최상 위 목록 에서 보 여 주 는 것 입 니 다.하 나 는 현재 노드 에서 최상 위 노드 의 이름 (또는 다른 속성) 까지 보 여 줍 니 다.예 를 들 어 국내의 습관 은 성에 서 시작 하여 시, 현, 주민 위원회 에 가 는 것 이 고 외국 의 습관 은 정반 대 이다. )。 상단 부터:
select sys_connect_by_path (title, '/')
from tb_menu
where id = 50
start with parent is null
connect by parent = prior id;
현재 노드 부터:
select sys_connect_by_path (title, '/')
from tb_menu
start with id = 50
connect by prior parent = id;
여기 서 나 는 또 불평 을 해 야 한다. Oacle 은 sys connect by path 함수 만 제공 하고 문자열 의 연결 순 서 를 잊 어 버 렸 다. 위의 예 에서 첫 번 째 sql 은 루트 노드 부터 옮 겨 다 니 는 것 이 고, 두 번 째 sql 은 현재 노드 를 직접 찾 는 것 이다. 효율 적 으로 는 천차만별 이다. 더 중요 한 것 은 첫 번 째 sql 은 하나의 노드 만 선택 할 수 있 고, 두 번 째 sql 은 현재 노드 만 선택 할 수 있다 는 것 이다.두 sql 은 나무 하 나 를 옮 겨 다 녔 습 니 다. 다시 ps.
sys connect by path 함 수 는 start with 가 시 작 된 곳 부터 옮 겨 다 니 며 옮 겨 다 니 는 노드 를 기록 하 는 것 입 니 다. start with 가 시 작 된 곳 은 루트 노드 로 간주 되 고 옮 겨 다 니 는 경 로 를 함수 의 구분자 에 따라 새로운 문자열 을 구성 하 는 기능 이 강 합 니 다.
11) 현재 노드 의 루트 노드 를 보 여 줍 니 다.
앞에서 말 했 듯 이 뿌리 노드 는 start with 가 시작 하 는 곳 입 니 다.
select connect_by_root title, tb_menu.*
from tb_menu
start with id = 50
connect by prior parent = id;
connect by root 함 수 는 열 앞 에 사용 되 고 현재 노드 의 뿌리 노드 의 내용 을 기록 합 니 다.
12) 현재 노드 가 잎 인지 보 여 줍 니 다.
이것 은 비교적 흔히 볼 수 있 습 니 다. 특히 동적 디 렉 터 리 에서 발 견 된 내용 이 하급 노드 가 있 는 지 여 부 를 알 아 낼 때 이 함 수 는 매우 적 용 됩 니 다.
select connect_by_isleaf, tb_menu.*
from tb_menu
start with parent is null
connect by parent = prior id;
connect by isleaf 함 수 는 현재 노드 에 하급 노드 가 포함 되 어 있 는 지 판단 하 는 데 사 용 됩 니 다. 포함 되 어 있 으 면 잎 노드 가 아니 라 여 기 는 0 으로 돌아 갑 니 다. 반대로 하급 노드 가 포함 되 어 있 지 않 으 면 여 기 는 1 로 돌아 갑 니 다.
이로써 Oacle 트 리 조 회 는 기본적으로 끝 났 습 니 다. 이상 의 예 에서 데 이 터 는 해 본 프로젝트 에 사 용 된 데이터 입 니 다. 안의 내용 이 이해 하기 어 려 울 수 있 기 때문에 모두 새로운 예 로 논술 합 니 다. 상기 모든 sql 은 본 컴퓨터 에서 테스트 를 통과 하고 해당 하 는 기능 을 실현 할 수 있 지만 이런 문 제 를 해결 하 는 가장 좋 은 방안 이 라 고 보장 할 수 없습니다.(8 조 와 같이 저장 프로 세 스 로 뚜렷하게 쓰 는 것 이 좋 습 니 다).

좋은 웹페이지 즐겨찾기