2009-04-02 2 views
-1

Скажем, у вас есть макет таблицы, как следующее:Как бы вы решили эту сложную проблему SQL?

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. Не вопрос о домашнем задании.

+0

Я мог бы сделать это довольно легко в T-SQL с футляром в избранных, но я не уверен, если MySQL поддерживает это ... –

+0

Я бы предпочел, чтобы результаты выплевывались в двух столбцах только CourseID и Instructor (s), а если их два, просто покажите их как разделенные запятыми. Это только мое предпочтение. – TheTXI

+0

Извините, почему он ниспровергнут? Его подлинный вопрос программирования, я не мог понять, как это сделать сам, поэтому я разместил его здесь –

ответ

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 

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

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

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 
+0

не может быть переведено на mysql –

1

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

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

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

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

+0

Мне нравится, как ваш ответ (связанный с статьей TheDailyWTF, связанный вопросник), как последний набор ответов (т. е. «Я бы посмотрел его онлайн, вот некоторые потенциально релевантные ссылки»). – JeeBee

+0

@RichB: Я предполагаю, что наши изменения столкнулись и что вы не хотели удалить последнюю ссылку. Не стесняйтесь редактировать снова, если я ошибаюсь, или удалить подпись ... –

+0

@JeeBee - Что я могу сказать? Мне слишком ленив, чтобы найти и скопировать код, но я не хочу, чтобы они тоже были пустыми. –

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

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

1- Я не верю, что какие-либо решения, представленные до сих пор, переносимы между диалектами SQL. Если было позволено считать 4-й столбец (*), я считаю, что следующее решение может быть довольно переносимым, так как оно в основном использует «стандартный SQL». Однако я тестировал только SQLite3.

2- Я намеренно придерживаюсь вашей спецификации, воспроизводя опечатку для стола couses. [Я предполагаю, что это должно было быть курсов вместо 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 
Смежные вопросы