우리는 트리 디렉터리나 제품 분류와 같은 2~3단계 메뉴를 만들었습니다. 더 많은 수준의 분류가 발생하면 일반적으로 재귀를 사용합니다. 프로그램에서 재귀를 사용하면 성능 오버헤드가 어느 정도 증가합니다.
이전에는 프로그램에서 비재귀적 무한급 분류 디렉터리를 구현하기 위해 ASP.net을 사용했는데, 이식성이 강하지 않다는 점을 고려하여 저장 프로시저로 변경하여 모두가 함께 공부할 수 있도록 보냈습니다. 테스트 과정에서 문제가 발견되지 않았습니다. 또한 코드가 최적화되지 않았습니다.
일반적으로 대부분의 작업은 디렉터리를 읽는 것이므로 다음 구현에서는 Select 문 하나만 읽으면 됩니다. 재귀가 없으면 레벨은 이론적으로 무한합니다~!
================================================= =====================
테이블 구조:
테이블 이름: Tb_Column
테이블 구조(모든 필드가 비어 있지 않음):
Column_ID int 기본 키(참고: 비식별자)
Column_Name nvarchar(50) 분류 이름
Parent_ID int 상위 카테고리 ID(기본값 0)
Column_Path nvarchar(1000) 분류 경로
Column_Depth int 분류 깊이(기본값 0)
Column_Order int 정렬(기본값 0)
Column_Intro nvarchar(1000) 분류 설명
========================================== === ===================
저장 프로시저 1: 새 분류 만들기
CREATE PROCEDURE sp_Column_Insert
(
@Parent_ID 정수,
@Column_Name nvarchar(50),
@Column_Intro nvarchar(1000)
)
처럼
@Err을 int로 선언
@Err=0으로 설정하여
트랜잭션 시작
--기존 레코드에서 열 ID를 가져옵니다.
@Column_ID를 int로 선언
@Column_Depth를 int로 선언
Tb_Column에서 @Column_ID = Max(Column_ID)를 선택합니다.
@Column_ID가 Null이 아닌 경우
@Column_ID = @Column_ID+1로 설정
또 다른
@Column_ID = 1 설정
- 최상위 열인지 확인하고 Column_Path 및 Column_Order를 설정합니다.
@Column_Path를 nvarchar(1000)로 선언합니다.
@Column_Order를 int로 선언
IF @Parent_ID = 0
시작하다
@Column_Path =Ltrim(Str(@Column_ID)) 설정
Tb_Column에서 @Column_Order = Max(Column_Order)를 선택합니다.
IF @Column_Order가 Null이 아닌 경우
@Column_Order = @Column_Order + 1 설정
Else --기록이 발견되지 않으면 이것이 첫 번째 기록임을 의미합니다.
@Column_Order = 1로 설정
- 깊이
@Column_Depth = 1로 설정
끝
또 다른
시작하다
--상위 노드의 경로와 깊이를 가져옵니다.
@Column_Path = Column_Path ,@Column_Depth = Column_Depth From Tb_Column 여기서
IF @Column_Path가 Null인 경우
시작하다
@Err = 1로 설정
끝으로 이동
종료
--동일한 상위 노드 아래의 최대 시퀀스 번호를 가져옵니다.
@Column_Order = Max(Column_Order) From Tb_PicColumn 여기서 Column_Path는
''+@Column_Path+'|%' 또는 Column_ID = @Parent_ID
와 같습니다.
IF @Column_Order Is Not Null - 시퀀스 번호가 존재하는 경우 시퀀스 번호 뒤의 모든 시퀀스 번호에 1을 추가합니다.
시작하다
--삽입할 현재 노드 이후의 모든 노드의 시퀀스 번호를 업데이트합니다.
Tb_Column 업데이트 Column_Order = Column_Order +1 여기서 Column_Order
>@Column_Order
--동일한 상위 노드 아래의 최대 시퀀스 번호에 1을 더한 값이 자체 시퀀스 번호를 형성합니다.
@Column_Order = @Column_Order + 1 설정
끝
또 다른
시작하다
@Err=1로 설정
끝으로 이동
끝
- 상위 노드의 경로와 자체 ID 번호가 자체 경로를 형성합니다.
@Column_Path = @Column_Path + '|' + Ltrim(Str(@Column_ID))
--깊이
설정
@Column_Depth = @Column_Depth+1
설정 끝
Tb_Column(Column_ID,Column_Name,Parent_ID,Column_Path,
Column_Depth,Column_Order,Column_Intro) 값(@Column_ID,@Column_Name,@Parent_ID,@Column_Path,@Column_Depth,@Column _Order,@Column_Intro에 삽입 )
IF @@Error<>0
시작하다
@Err=1로 설정
끝으로 이동
종료
--현재 레코드 이후의 레코드 순서를 업데이트합니다.
--Tb_Column 업데이트 Column_Order = Column_Order+1 여기서 Column_Order > @Column_Order
theEnd:
IF @Err=0
시작하다
거래 커밋
@Column_ID 반환
끝
또 다른
시작하다
트랜 롤백
0을 반환
끝
가기
================================================ ============================
저장 프로시저 2: 카테고리 삭제
생성 절차 sp_Column_Delete
(
@Column_ID 정수
)
처럼
@Err을 int로 선언
@Err = 0으로 설정
트랜 시작
--먼저 노드 아래에 자식 노드가 있는지 확인합니다.
Parent_ID = @Column_ID인 Tb_Column에서 Column_ID를 선택합니다.
IF @@RowCount<>0
시작하다
@Err = 1로 설정
끝으로 이동
끝
-- 삭제 후 다른 레코드의 순서를 정렬하기 위해 노드의 Column_Order를 가져옵니다.
@Column_Order를 int로 선언
Column_ID = @Column_ID인 Tb_Column에서 @Column_Order = Column_Order를 선택합니다.
@Column_Order가 NULL인 경우
시작하다
@Err =2로 설정
끝으로 이동
끝
- 다른 레코드의 Column_Order 업데이트
Tb_Column 업데이트 Column_Order = Column_Order -1 여기서 Column_Order >@Column_Order
IF @@오류<>0
시작하다
@Err =3으로 설정
끝으로 이동
종료
--삭제 작업
Column_ID=@Column_ID 인 Tb_Column에서 삭제
IF @@오류<>0
시작하다
@Err =4로 설정
끝으로 이동
종료
--다른 레코드의 Column_ID 업데이트
--Tb_Column 세트 업데이트 Column_ID= Column_ID - 1 여기서 Column_ID >@Column_ID
--IF @@오류<>0
-- 시작하다
-- @Err =5로 설정
-- 끝으로 이동
-- 끝 끝
:
IF @Err = 0
시작하다
거래 커밋
0 반환 - 성공적으로 삭제되었습니다.
끝
또 다른
시작하다
IF @Err=1
시작하다
트랜 롤백
반환 1 - 하위 노드가 있음
끝
또 다른
시작하다
트랜 롤백
반환 2--알 수 없는 오류
끝
끝
가다
================================================= ================
저장 프로시저 3: 분류 편집
절차 만들기 sp_Column_Update
(
@Column_ID 정수,
@Parent_ID 정수,
@Column_Name nvarchar(50),
@Column_Intro nvarchar(1000)
)
처럼
@Err을 int로 선언
@Err=0으로 설정
Begin Tran
--수정 전 값 가져오기: Parent_ID, Column_Depth, Column_Order
@oParent_ID를 int로 선언
@oColumn_Depth를 int로 선언
@oColumn_Order를 int로 선언
@oColumn_Path를 nvarchar(1000)로 선언
@oParent_ID = Parent_ID, @oColumn_Depth = Column_Depth,@oColumn_Order = Column_Order, @oColumn_Path = Column_Path From Tb_Column Where Column_ID = @Column_ID
@oParent_ID가 Null인 경우
시작하다
@Err = 1로 설정
끝으로 이동
종료
- 상위 ID가 변경되지 않은 경우 열 이름과 열 소개를 직접 수정합니다.
IF @oParent_ID = @Parent_ID
시작하다
Tb_Column 업데이트 Column_Name = @Column_Name,Column_Intro = @Column_Intro 여기서 Column_ID = @Column_ID
IF @@오류 <> 0
@Err = 2로 설정
끝으로 이동
끝
@nColumn_Path를 nvarchar(1000)로 선언합니다.
@nColumn_Depth를 int로 선언
@nColumn_Order를 int로 선언
- 현재 노드에 포함된 노드 수를 상위 노드(자체 포함)로 가져옵니다. 참고: "1"이 반환되면 단일 노드라는 의미입니다.
@theCount를 int로 선언하세요.
Column_ID=@Column_ID 또는 ''+@oColumn_Path+'|%' 와 같은 Column_Path인 Tb_Column에서 @theCount = Count(Column_ID)를 선택합니다.
@theCount가 Null인 경우
시작하다
@Err = 3으로 설정
끝으로 이동
End
IF @Parent_ID=0 --최상위 노드로 설정된 경우 마지막 최상위 노드로 설정합니다.
시작하다
--'최상위 열로 설정' 인쇄
@nColumn_Path = Ltrim(Str(@Column_ID)) 설정
@nColumn_Depth =1로 설정
Tb_Column에서 @nColumn_Order = Max(Column_Order) 선택
@nColumn_Order가 NULL인 경우
시작하다
@Err = 4로 설정
끝으로 이동
End
Set @nColumn_Order = @nColumn_Order - @theCount + 1
--세 부분 업데이트 1 노드 자체 2 모든 하위 노드 2 이 트리가 변경되기 전 후속 레코드의 순서
--'이 열의 이전 위치 뒤의 모든 열 업데이트[이 열 아래의 하위 열 제외]: Column_Order'를 인쇄합니다.
Tb_Column 세트 Column_Order = Column_Order-@theCount Where (Column_Order >@oColumn_Order) And (Column_Path Not like ''+@oColumn_Path+'|%' ) 업데이트
IF @@오류 <> 0
시작하다
@Err = 7로 설정
끝으로 이동
End
--'이 열 업데이트: Parent_ID, Column_Path, Column_Depth, Column_Order, Column_Name, Column_Intro' 인쇄
'Order : '+Ltrim(Str(@nColumn_Order)) 인쇄
Tb_Column 세트 업데이트 Parent_ID=@Parent_ID,Column_Path = @nColumn_Path,Column_Depth = @nColumn_Depth,Column_Order = @nColumn_Order, Column_Name = @Column_Name,Column_Intro = @Column_Intro 여기서 Column_ID = @Column_ID
IF @@오류 <> 0
시작하다
@Err = 5로 설정
끝으로 이동
End
--'이 열 아래의 모든 하위 열 업데이트: Column_Path, Column_Depth, Column_Order'를 인쇄합니다.
Tb_Column 세트 업데이트 Column_Path = 바꾸기(Column_Path,@oColumn_Path,@nColumn_Path),Column_Depth = Column_Depth + (@nColumn_Depth-@oColumn_Depth),Column_Order = Column_Order+( @nColumn_Order-@oColumn_Order) 여기서 Column_Path는 ''+@oColumn_Path+'|%'와 같습니다.
IF @@오류 <> 0
시작하다
@Err = 6으로 설정
끝으로 이동
끝
끝
또 다른
시작하다
--미래 상위 노드의 관련 정보를 가져오고 이 노드의 관련 값을 설정합니다.
@nColumn_Depth = Column_Depth,@nColumn_Path = Column_Path From Tb_Column 여기서 Column_ID = @Parent_ID를 선택합니다.
@nColumn_Depth가 NULL이거나 @nColumn_Path가 Null인 경우
시작하다
@Err = 8로 설정
끝으로 이동
끝
@nColumn_Depth = @nColumn_Depth +1 설정
@nColumn_Order =Max(Column_Order) From Tb_Column 여기서 Column_ID = @Parent_ID 또는 ''+@nColumn_Path+'|%' 와 같은 Column_Path를 선택합니다.
@nColumn_Order가 NULL인 경우
시작하다
@Err = 9로 설정
끝으로 이동
End
Set @nColumn_Path = @nColumn_Path +'|'+ Ltrim(Str(@Column_ID))
IF @nColumn_Order = @oColumn_Order+1 --새 상위 노드가 원래 위치보다 가장 가까운 형제 노드인 경우 모든 노드의 순서는 다음과 같습니다. 달라져라.
시작하다
Tb_Column 세트 업데이트 Parent_ID=@Parent_ID,Column_Path = @nColumn_Path,Column_Depth = @nColumn_Depth, Column_Name = @Column_Name,Column_Intro = @Column_Intro 여기서 Column_ID = @Column_ID
IF @@오류 <> 0
시작하다
@Err = 10으로 설정
끝으로 이동
끝
End
Set @nColumn_Order = @nColumn_Order + 1
--세 부분 업데이트 1 이 트리가 변경되기 전 다음(또는 이전) 레코드의 순서 1 노드 자체 3 모든 하위 노드
--상향운동과 하향운동으로 구분
--'이 열의 이전 위치[또는 이 열 뒤의 위치] 뒤의 모든 열 업데이트 [이 열 아래의 하위 열 제외]: Column_Order'를 인쇄합니다.
IF @nColumn_Order < @oColumn_Order
시작하다
Tb_Column 세트 Column_Order = Column_Order+@theCount 여기서 Column_Order<@oColumn_Order 및 Column_Order >=@nColumn_Order And (Column_Path Not like ''+@oColumn_Path+'|%' ) 및 Column_ID<>@Column_ID
IF @@오류 <> 0
시작하다
@Err = 12로 설정
끝으로 이동
끝
끝
또 다른
시작하다
Tb_Column 세트 Column_Order = Column_Order-@theCount 여기서 Column_Order >@oColumn_Order 및 Column_Order<@nColumn_Order And (Column_Path Not like ''+@oColumn_Path+'|%' ) 및 Column_ID<>@Column_ID
IF @@오류 <> 0
시작하다
@Err = 13으로 설정
끝으로 이동
끝
End
--'이 열 업데이트: Parent_ID, Column_Path, Column_Depth, Column_Order, Column_Name, Column_Intro' 인쇄
'Order : '+Ltrim(Str(@nColumn_Order)) 인쇄
IF @nColumn_Order > @oColumn_Order
@nColumn_Order = @nColumn_Order - @theCount 설정
Tb_Column 세트 업데이트 Parent_ID=@Parent_ID,Column_Path = @nColumn_Path,Column_Depth = @nColumn_Depth,Column_Order = @nColumn_Order, Column_Name = @Column_Name,Column_Intro = @Column_Intro 여기서 Column_ID = @Column_ID
IF @@오류 <> 0
시작하다
@Err = 10으로 설정
끝으로 이동
End
--'이 열 아래의 모든 하위 열 업데이트: Column_Paht, Column_Depth, Column_Order'를 인쇄합니다.
Tb_Column 세트 업데이트 Column_Path = 바꾸기(Column_Path,@oColumn_Path,@nColumn_Path),Column_Depth = Column_Depth + (@nColumn_Depth-@oColumn_Depth),Column_Order = Column_Order+(@nColumn_Order-@oColumn_Order) 여기서 Column_Path는 ''+@oColumn_Path+'|%'와 같습니다.
IF @@오류 <> 0
시작하다
@Err = 11로 설정
끝으로 이동
끝
끝을
끝내다
:
IF @Err<>0 --오류가 있는 경우 오류 번호를 반환합니다.
시작하다
트랜 롤백
@Err 반환
끝
Else --오류가 없으면 0을 반환합니다.
시작하다
거래 커밋
0을 반환
끝
가다
================================================= =========================
저장 프로시저 4: 표시 분류(단지 select 문)
카테고리 목록:
절차 생성 sp_Column_List
처럼
SELECT 열_ID, 열_이름, 상위_ID, 열_경로, 열_깊이,
컬럼_순서, 컬럼_소개
Tb_Column에서
ORDER BY 열_순서
가기
========================================
다음은 친구 포럼에 게시된 ASP.NET에서의 사용 예입니다.
http://www.mzline.com/bbs/dispbbs.asp?boardID=67&ID=5044&replyID=25788&star=1&skin=0#25788