Как бы вы решили эту сложную проблему SQL? - PullRequest
0 голосов
/ 02 апреля 2009

Скажем, у вас есть макет таблицы, подобный следующему:

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 ]

7 голосов
/ 02 апреля 2009

Да, да, бизнес-логика и т. Д. Это игра, а не ваш начальник просит вас сделать это.

В 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
3 голосов
/ 02 апреля 2009

В 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 

Обратите внимание, что это выбирает «profs» в качестве списка профессоров (как указано в вопросе) в виде одного столбца.

Я недостаточно знаком с MySQL, чтобы знать, существует ли эквивалент функции list().

2 голосов
/ 02 апреля 2009

Я думаю, что это будет работать, но я еще не проверял это. Это не очень масштабируемо, если вы решите начать показывать 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
1 голос
/ 02 апреля 2009

Не самый лучший запрос в мире, но во всем этом безобразие мне нравится. В частности, мне нравится тот факт, что вам не нужно иметь дело с несколькими утверждениями кейса, что может быть проблемой, если у вас есть много полей, к которым вы должны применить кейс:

--- 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
1 голос
/ 02 апреля 2009

Что вам нужно, так это отчет "Сводная таблица" или "Кросс-таблица". Они доступны с использованием обычного SQL:

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

Здесь, вероятно, есть и другие вопросы о SO, а также дополнительная информация. Ознакомьтесь с информацией здесь, которая показывает, как вы можете сделать это в SQL или в логике приложения (через последовательные запросы):

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

0 голосов
/ 02 апреля 2009

Еще одна альтернатива. Примечание:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...