2011-09-30 10 views
3

내 문제는 '재귀 쿼리'로 해결되지만 MySQL은 재귀 쿼리를 지원하지 않으므로 인접 목록 모델을 사용하려고했기 때문에 생각합니다. 내가 얼마나 깊이 가고 싶은지 알고 있기 때문에 이것은 문제가되지 않아야한다. 여기 MYSQL의 재귀 쿼리?

내가해야 할 일의 예 : 표 수업 :

dept classNum prereqDept prereqClassNum 
BIO  465   BIO   335 
EE  405   EE   325 
EE  325   EE   120 
BIO  465   EE   120 
BIO  335   BIO   225 
BIO  225   CHEM  110 
BIO  225   BIO   105 

는 내가 필요로하는 특정 수준의 모든 클래스입니다 최대 3 레벨 깊은 모든 전제 조건 (의 400을 가정 해 봅시다) . 그래서 나는 내가 3 개 수준에 깊은 가고 싶은 경우 3-LEFT 조인을 사용할 필요가 알고

dept classNum prereqDept prereqClassNum 
BIO  465   BIO   335 
BIO  465   BIO   225 
BIO  465   CHEM  110 
BIO  465   BIO   105 
EE  405   EE   325 
EE  405   EE   120 
.... 

같은 것을 얻을 것입니다,하지만 난이 무엇을 얻기 위해 조인 설정하는 방법을 알아낼 수 없습니다 나는 필요하다. 아이디어가 있으십니까? 나는 당신의 도움을 줄 것입니다!

P. 나는 테이블 구조를 전혀 바꿀 수 없다.

+0

그냥 궁금 해서요. 몇 줄을 여기서 말하고 있습니까? 너무 많은 데이터가 없으면 1 개의 쿼리에서 잠재적으로 적용 가능한 모든 행을 선택하고 필요에 따라 결과 집합을 처리하여 필요한 결과 구조를 얻는 것이 더 쉽습니다. – scunliffe

+0

@scunliffe 간단한 쿼리를 만들어 모든 테이블을 검색 한 다음 서버 코드를 사용하여 결과를 만드는 것을 의미합니까? 나는 하나의 쿼리로 모든 것을해야한다. – Eric

답변

1

흠. 단지에 따라 쌍을 복사하여, 5, 6을

SELECT * FROM 
(
    (
     SELECT t1.dept, t1.classNum, t1.prereqDept, t1.prereqClassNum 
     FROM class AS t1 
     WHERE t1.classNum >= 400 
    ) 
    UNION 
    (
     SELECT t1.dept, t1.classNum, t2.prereqDept, t2.prereqClassNum 
     FROM class AS t1 
     JOIN class AS t2 ON (t1.prereqDept = t2.dept AND t1.prereqClassNum = t2.classNum) 
     WHERE t1.classNum >= 400 
    ) 
    UNION 
    (
     SELECT t1.dept, t1.classNum, t3.prereqDept, t3.prereqClassNum 
     FROM class AS t1 
     JOIN class AS t2 ON (t1.prereqDept = t2.dept AND t1.prereqClassNum = t2.classNum) 
     JOIN class AS t3 ON (t2.prereqDept = t3.dept AND t2.prereqClassNum = t3.classNum) 
     WHERE t1.classNum >= 400 
    ) 
) AS t4 
ORDER BY dept, classNum, prereqDept, prereqClassNum 
+0

마지막 UNION에서는 t3.prereqClassNum에 대해 t3.prereqDept를 변경해야했지만 완벽하게 작동한다는 것 외에도! 감사! – Eric

+0

아. 내 오타가 수정되었습니다. 내 첫 시도가 완벽하게 작동하는 따뜻한 솜털 같은 느낌을줍니다. =) –

1

내가 할 수있는 방법 (더 쉬운 것이 있는지 확실하지 않음).

SELECT * FROM table; 

그런 다음 두 수준 아래

을 :

SELECT t.dept AS dept, t.classNum AS classNum, t2.prereqDept AS prereqDept, t2.prereqClassNum AS prereqClassNum FROM table AS t 
LEFT JOIN table AS t2 WHERE t2.classNum = t.prereqClassNum; 

재사용 세 수준 아래로 갈 :

SELECT t3.dept AS dept, t3.classNum AS classNum, t4.prereqDept AS prereqDept, t4.prereqClassNum AS prereqClassNum 
FROM (
    SELECT t.dept AS dept, t.classNum AS classNum, t2.prereqDept AS prereqDept, t2.prereqClassNum AS prereqClassNum FROM table AS t 
    LEFT JOIN table AS t2 WHERE t2.classNum = t.prereqClassNum 
) AS t3 
LEFT JOIN table AS t4 WHERE t4.classNum = t3.prereqClassNum; 

을 마지막으로, 당신은 그냥 할 수있는 첫 번째 (쉬운) 한 수준의 종속성을 얻을 세 가지 쿼리 모두의 UNION입니다.

(SELECT * FROM table) 
UNION 
(SELECT t.dept AS dept, t.classNum AS classNum, t2.prereqDept AS prereqDept, t2.prereqClassNum AS prereqClassNum FROM table AS t 
LEFT JOIN table AS t2 WHERE t2.classNum = t.prereqClassNum) 
UNION 
(SELECT t3.dept AS dept, t3.classNum AS classNum, t4.prereqDept AS prereqDept, t4.prereqClassNum AS prereqClassNum 
FROM (
    SELECT t.dept AS dept, t.classNum AS classNum, t2.prereqDept AS prereqDept, t2.prereqClassNum AS prereqClassNum FROM table AS t 
    LEFT JOIN table AS t2 WHERE t2.classNum = t.prereqClassNum 
) AS t3 
LEFT JOIN table AS t4 WHERE t4.classNum = t3.prereqClassNum); 

나는 그것이 작동 확인하지 않았다 ...하지만 그 같은 일을해야 ...

+0

아이디어는 정확하다, 감사하다 !!! – Eric

2

내가 이것을 실행했습니다과 3 전제 조건까지 (이 샘플에서) 모든 클래스를 얻을 수 있지만, 4로 확장 될 수있다 :이 시도 "IDSeq =?".

중요한 요소는 그룹이 변경 될 때마다 처음에 1부터 시작하는 일반적인 Dept + ClassNum을 기반으로 각 레코드에 할당 된 번호를 얻는 것입니다. 이렇게하려면 SQL 변수를 먼저 적용했습니다. 각 그룹은 1, 2, 3 ... 1, 2, ... 1, ... 1, 2, 3, 4, 5 순으로 정렬되어 있는지 확인하십시오. 이 작업이 완료되면. 등 ... 내부 쿼리의

결과가

Result of inner query

, 우리는 다른 복잡한 등 unioning, 가입, 가입하지에 의해 간단하게 그룹을 할 수 있습니다 ... 그냥 적용 알려진 시퀀스에 기초한 IF()의 max(). 패턴을 볼 수 있듯이, 필자는 Dept와 ClassNum이 "1"레코드이고, "2"와 "3"이 다시 제공되지만, 적용 할 수있는 행이 무엇이든 가져옵니다.

max (if())를 사용하면 모든 클래스는 항상 1 개의 시퀀스를 가지지 만 때로는 2 개 뿐이지 만 3, 4 또는 5입니다. 따라서 값이 없으면 적어도 공백으로 채워 지므로 null이 표시되지 않습니다. 그렇다면 값이있을 때 MAX()는 공백이있을 때 공백을 대체합니다 ...

최종 검색어는 놀랍고 아마도 필요한 것 일 것입니다.

select 
     NewSet.Dept, 
     NewSet.ClassNum, 
     max(if(NewSet.IDSeq = 1, NewSet.PreReqDept, ' ')) FirstDept, 
     max(if(NewSet.IDSeq = 1, NewSet.PreReqClassNum, ' ')) FirstClassNum, 
     max(if(NewSet.IDSeq = 2, NewSet.PreReqDept, ' ')) SecondDept, 
     max(if(NewSet.IDSeq = 2, NewSet.PreReqClassNum, ' ')) SecondClassNum, 
     max(if(NewSet.IDSeq = 3, NewSet.PreReqDept, ' ')) ThirdDept, 
     max(if(NewSet.IDSeq = 3, NewSet.PreReqClassNum, ' ')) ThirdClassNum 
    from 
     (select 
      @orig := @orig +1 as OrigSeq, 
      @seq := if(concat(P.Dept, P.ClassNum) = @LastGrp, @seq +1, 1) as IDSeq, 
      @LastGrp := concat(P.Dept, P.ClassNum) NextGrp, 
      P.Dept, 
      P.ClassNum, 
      P.PreReqDept, 
      P.PreReqClassNum 
      from 
      PreReqs P, 
      (select @orig := 0, @seq := 0, @LastGrp := '') x 
      order by 
      Dept, 
      ClassNum) NewSet 
    group by 
     NewSet.Dept, 
     NewSet.ClassNum 
    order by 
     NewSet.Dept, 
     NewSet.ClassNum 
+0

우수하지만,이 솔루션을 사용하는 방법에 대해 궁금한 점이 있습니까? :) – Eric

+0

@ 에릭, 무슨 존경에서, 당신은 명확히 할 수 있고, 나는 해명과 함께 나의 대답을 업데이트 할 것이다. – DRapp