2011-09-30 129 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 

我需要一定级别的所有类是(比方说400)与他们的所有先决条件达到3级深。 所以我得到的东西像

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 
.... 

我知道我需要使用3-LEFT JOIN的,如果我想要去的3个层次深,但我想不出如何建立这些连接得到什么我需要。 任何想法? 我会Appreacite你的帮助!

P.S.我根本无法改变表格结构。

+0

只是好奇......我们在这里谈了多少行?如果没有太多数据,则可以更容易地选择1个查询中的所有可能适用的行,并根据需要处理结果集以获取所需的结果结构。 – scunliffe

+0

@scunliffe你的意思是创建一个简单的查询来检索所有的表,然后使用服务器代码来创建我的结果? 我必须在一个查询中做到这一切 – Eric

回答

1

嗯。只是通过复制基础上,对

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.prereqDept更改为t3.prereqClassNum,但除此之外,它完美地工作!谢谢! – 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; 

,你可以做一个级别(易)首先得依赖所有这三个查询的联合。

(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,5,6:试试这个“IDSeq =?”。

这里的关键要素是根据公用部门+班级号码每次在组变化开始时从1开始获取分配给每条记录的号码。为此,我将SQL变量应用于FIRST确保每个组的排序顺序为1,2,3 ... 1,2,... 1,... 1,2,3,4,5。 。等等

内部查询的结果

Result of inner query

一旦做到这一点,我们可以通过没有其他复杂的加盟,加盟,unioning等做了简单的组...只要申请基于已知序列的IF()的max()。正如你所看到的模式,我得到了它的先决条件Dept和ClassNum所提供的那个是“1”st记录,然后再次在“2”和“3”rd,但可以应用通过使用max(if()),每个类将总是有1个序列,但只有有时会有2个,更不用说3个了, 4或5.所以,如果没有值,它至少会被空格填充,所以它不会显示为空。然后,如果/当存在一个值时,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

@Eric,从哪方面来说,你能否澄清,我会通过澄清更新我的答案。 – DRapp