(super_id, user_id) 집합에서 가능한 경로의 사각형을 만드는 몇 가지 간단한 프로세스 P를 생각해보십시오.
길이 N의 경로는 N 레벨 깊이이며 링크 (N-1) 관계입니다.
각 레벨의 값이 해당 레벨과 다른가요?
- 아니요? P는 실제 경로와 비교할 때 사이클, 크로스 오버 경로 및 랩 어라운드 경로를 찾습니다. 랩 어라운드는 실제 경로 레벨> 1에있는 노드가 '발견'되어 레벨 = 1 노드가되는 경우입니다.
- 예? P는 경로, 크로스 오버 경로 및 랩 어라운드 경로를 찾습니다. 추가 데이터 제한 또는 규칙은
가 뚜렷 수준의 값으로 4 개 간단한 경로를 고려 제거하는 데 도움이 될 수 있습니다 :
data path(keep=L1-L4) rels(keep=super_id user_id);
array L(4);
input L(*);
output path;
super_id = L(1);
do i = 2 to dim(L);
user_id = L(i);
output rels;
super_id = user_id;
end;
datalines;
1 3 1 4
1 5 1 4
2 3 2 3
1 2 3 4
run;
는 관계 데이터 만의 12 가지가 있습니다. 나도 그들이 존재하는이 쌍에 살고있는 경로도 수준을 알 수 없습니다 :
1 : 1 3
2 : 3 1
3 : 1 4
4 : 1 5
5 : 5 1
6 : 1 4
7 : 2 3
8 : 3 2
9 : 2 3
10 : 1 2
11 : 2 3
12 : 3 4
관계 사이에 4 개 레벨 경로를 조립 명시 적 2 단계 쿼리. 코드가 작동하면 매크로 코딩을 위해 추상화 될 수 있습니다.
proc sql;
* RELS cross RELS, extensive i/o;
* get on the induction ladder;
create table ITER_1 as
select distinct
S.super_id as L3 /* parent^2 */
, S.user_id as L2 /* parent */
, U.user_id as L1 /* leaf */
from RELS U
cross join RELS S
where S.user_id = U.super_id
order by L3, L2, L1
;
* ITER_1 cross RELS, little less extensive i/o;
* if you see the inductive variation you can macroize it;
create table ITER_2 as
select distinct
S.super_id as L4 /* parent^3 */
, U.L3 /* parent^2 */
, U.L2 /* parent */
, U.L1 /* leaf */
from ITER_1 U
cross join RELS S
where S.user_id = U.L3
order by L4, L3, L2, L1
;
quit;
위 어셈블러에는 쌍 ID 지식이 없으므로 개별 쌍의 경로로 제한 할 수 없습니다. 그래서 사이클, 크로스 오버 및 랩이있을 것입니다.
발견 경로 (일부 설명) 각각의 관계 레벨의 ID를 다음 사이클 암시 제거 다른 단계에서 발견되지 않으면
1 : 1 2 3 1 path 4 L3 xover to path 1 L2
2 : 1 2 3 2 path 4 L3 xover to path 3 L2
3 : 1 2 3 4 actual
4 : 1 3 1 2 path 1 L3 xover to path 4 L1
5 : 1 3 1 3
6 : 1 3 1 4 actual
7 : 1 3 1 5
8 : 1 3 2 3
9 : 1 5 1 2
10 : 1 5 1 3
11 : 1 5 1 4 actual
12 : 1 5 1 5
13 : 2 3 1 2
14 : 2 3 1 3
15 : 2 3 1 4
16 : 2 3 1 5
17 : 2 3 2 3 actual is actually a cycler too
18 : 3 1 2 3
19 : 3 1 3 1
20 : 3 1 3 2
21 : 3 1 3 4
22 : 3 1 5 1
23 : 3 2 3 1
24 : 3 2 3 2
25 : 3 2 3 4
26 : 5 1 2 3
27 : 5 1 3 1
28 : 5 1 3 2
29 : 5 1 3 4
30 : 5 1 5 1 path 2 L3 cycled to path 2 L1
. 경로 ID 정보가 없으므로 교차 전달을 제거 할 수 없습니다. 랩 어라운드 (wrap-arounds)와 동일합니다.
더 복잡한 SQL은 발견 된 '경로'의 각 관계가 단 한 번만 나타나고 경로의 내용이 고유함을 보장 할 수 있습니다. 실제 데이터에 따라 여전히 많은 수의 잘못된 경로가있을 수 있습니다.
매우 정규 코드는 매크로화에 적합하지만 실제 SQL 실행 시간은 실제 데이터 및 REL 데이터 세트 색인화에 크게 의존합니다.
proc sql;
create table ITER_1 as
select
L3 /* parent^2 */
, L2 /* parent */
, L1 /* leaf */
, R1
, R2
from
(
select distinct
S.super_id as L3 /* parent^2 */
, S.user_id as L2 /* parent */
, U.user_id as L1 /* leaf */
, U.row_id as R1
, S.row_id as R2
, monotonic() as seq
from RELS U
cross join RELS S
where S.user_id = U.super_id
and S.row_id < U.row_id /* triangular constraint allowed due to symmetry */
)
group by L3, L2, L1
having seq = min(seq)
order by L3, L2, L1
;
create table ITER_2 as
select
L4 /* parent^3 */ format=6.
, L3 /* parent^2 */ format=6.
, L2 /* parent */ format=6.
, L1 /* leaf */ format=6.
, R1 format=6.
, R2 format=6.
, R3 format=6.
from
(
select distinct
S.super_id as L4 /* parent^3 */ format=6.
, U.L3 /* parent^2 */ format=6.
, U.L2 /* parent */ format=6.
, U.L1 /* leaf */ format=6.
, U.R1 format=6.
, U.R2 format=6.
, S.row_id as R3 format=6.
, monotonic() as seq
from ITER_1 U
cross join RELS S
where S.user_id = U.L3
and S.row_id ne R1
and S.row_id ne R2
)
group by L4, L3, L2, L1
having seq = min(seq)
order by L4, L3, L2, L1
;
종료;
NULL 항목의 최종 수정에는 더 많은 SQL이 필요합니다.
NULL이 없어도 발견 된 계층 구조를 처리 할 수 있습니까? BY 처리로 설정된 DATA 스텝은 LAST를 사용하여 레벨의 끝을 감지 할 수 있습니다.
SAS의 proc SQL은 장난감 구현입니다. * 깨끗하게 보일 수도 있지만 anti-join은 인식하지 못합니다. 무시해. 많은 데이터 - 단계 (많은 임시 테이블)를 사용하는 것이 운명 일 것입니다. – wildplasser
샘플 데이터와 예상 출력을 게시하면 좀 더 잘 할 수 있습니다. 이 치수 유형 테이블을 변경하는 속도가 느려지고 있다고 가정하고 있습니까? 이를 달성하기 위해 SQL이 아닌 SAS 기능을 사용하는 다른 방법이 있습니다. – Reeza
SAS에서의 진정한 재귀 (링크 된 목록 또는 이진 트리와 같은)는 SQL의 유무에 상관없이 고통 스럽습니다. Python이나 Mongo DB 같은 것을 사용하는 것이 더 낫습니다. Map/Reduce는 이런 종류의 일을 훨씬 쉽게 만듭니다. – david25272