你会如何解决这个棘手的SQL问题?

时间:2009-04-02 18:13:29

标签: sql mysql database

假设你有一个如下所示的表格布局:

couses

id (INT), 
courseName (VARCHAR)

指导员:

id (INT),
courseId(INT),
instructor(VARCHAR)

创建一个将打印所有课程的查询,如果有一位教师,则显示他们的姓名,如果有两位教师,则按排序顺序在行上打印他们的名字,如果有两位以上的教师而不是教师姓名显示“委员会”。

例如,您的输出看起来像这样

    courseId    instructor1        instructor2 
    0           Edward Yourdon  
    1           Edward Dijkstra    Nicholas Wirth 
    2           Comittee    

注意:摘自TheDailyWtf的调查问卷。不是作业问题。

6 个答案:

答案 0 :(得分:7)

是的,是的,商业逻辑等。这是一个游戏,而不是你老板要求你这样做。

在T-SQL中:

 select
    id
     , courseName
     , case (select count(*) from instructors i where i.courseid=c.courseid)
         when 0 then 'No Instructor'
         when 1 then (select top 1 instructor from instructors where i.courseid=c.courseid)
         when 2 then (select top 1 instructor from instructors where i.courseid=c.courseid order by instructor desc)
         else 'Committee'
         end as instructor_1
     , case (select count(*) from instructors i where i.courseid=c.courseid)
         when 2 then (select top 1 instructor from instructors where i.courseid=c.courseid order by instructor asc)
         else ''
         end as instructor_2
 from courses c

答案 1 :(得分:3)

在SQL Anywhere中,您可以通过以下方式执行此操作:

select courseid as cid,
if ( select count(*) from instructor where courseid = cid ) > 2 
   then 'Committee' 
else 
   list(name order by name) 
endif as profs
from instructor
group by courseid
order by cid 

请注意,这会选择“教授”作为教授名单(如问题所述)作为单一栏目。

我对MySQL不太熟悉,知道是否有与list()函数等价的内容。

答案 2 :(得分:2)

我认为这会奏效,但我还没有测试过。如果您决定要开始显示3个教师或4个或更多教师,那么它的可扩展性不是很高。

SELECT
    C.id AS course_id,
    CASE
        WHEN I3 IS NOT NULL THEN 'Committee'
        ELSE I1.instructor + COALESCE(', ' + I2.instructor, '')
    END AS instructors
FROM
    Courses C
LEFT OUTER JOIN Instructors I1 ON
    I1.course_id = C.id
LEFT OUTER JOIN Instructors I_CHK1 ON
    I_CHK1.course_id = C.id AND
    I_CHK1.instructor < I1.instructor
LEFT OUTER JOIN Instructors I2 ON
    I2.course_id = C.id AND
    I2.instructor > I1.instructor
LEFT OUTER JOIN Instructors I_CHK2 ON
    I_CHK2.course_id = C.id AND
    I_CHK2.instructor > I1.instructor AND
    I_CHK2.instructor < I2.instructor
LEFT OUTER JOIN Instructors I_CHK2 ON
    I3.course_id = C.id AND
    I3.instructor > I2.instructor AND
WHERE
    I_CHK1.id IS NULL AND
    I_CHK2.id IS NULL

答案 3 :(得分:1)

您要查找的是“数据透视表”或“交叉表”报告。它们可以使用普通的SQL:

  

http://en.wikibooks.org/wiki/MySQL/Pivot_table

此处可能还有其他问题,还有更多信息。查看此处的信息,其中显示了如何在SQL或应用程序逻辑中执行此操作(通过连续查询):

  

https://stackoverflow.com/search?q=pivot+table

答案 4 :(得分:1)

这不是世界上最好的查询,但在所有的丑陋中,我有点喜欢它。具体来说,我喜欢这样一个事实,即您不必处理多个案例陈述,如果您有许多字段需要应用案例,这可能会很痛苦:

--- Single instructor case.
select
    c.id as courseId, i.instructor as instructor1, null as instructor2
from
    courses as c inner join instructors as i on i.courseId = c.id
where
    (
        select 
            count(instructor) 
        from 
            instructors as i2 
        where 
            i2.courseId = c.id
    ) = 1
union
--- Committee case.
select
    c.id as courseId, "committee" as instructor1, null as instructor2
from
    courses as c inner join instructors as i on i.courseId = c.id
where
    (
        select 
            count(instructor) 
        from 
            instructors as i2 
        where 
            i2.courseId = c.id
    ) > 2
union
--- Two instructor case.
select
    c.id as courseId, i1.instructor as instructor1, 
    i2.instructor as instructor2
from
    courses as c, instructor as i1, instructor as i2
where
    --- Course ids must match.
    c.id = i1.courseId and c.id = i2.courseId and

    --- Instructor ids do not match.
    i1.id <> i2.id and

    --- There are only two instructors.
    (
        select 
            count(instructor) 
        from 
            instructors as i2 
        where 
            i2.courseId = c.id
    ) > 2

答案 5 :(得分:0)

另一种选择。注意:

1-我不相信到目前为止提供的任何解决方案都可以在SQL方言之间移植。如果允许第4列计数(*),我相信以下解决方案可以非常便携,因为它主要使用“标准SQL”。但是我只在SQLite3上测试过。

2-我故意通过复制couses表的错误来坚持你的规范。 [我猜它本来是课程而不是课程]

select 
  c.id, c.courseName, i.instructor as instructor1, null as instructor2 
from 
  couses c, instructors i 
where 
  c.id = i.courseId 
group by 
  courseId having count(*) = 1
union
select /* Case 2: Two instructors */
  c.id, c.courseName, i1.instructor as instructor1, i2.instructor as instructor2 
from 
  couses c, instructors i1, instructors i2 
where 
  c.id = i1.courseId and c.id = i2.courseId and i1.id != i2.id and i1.id < i2.id 
group by 
  c.id having count(*) = 1
union
select /* Case 3: Three or more instructors */
  c.id, c.courseName, "Commitee" as instructor1, null as instructor2 
from 
  couses c, instructors i1, instructors i2, instructors i3 
where 
  c.id = i1.courseId and c.id = i2.courseId and c.id = i3.courseId and 
  i1.id != i2.id and i1.id != i3.id and i2.id != i3.id and i1.id < i2.id 
  and i2.id < i3.id