2009-04-02 4 views
-1

Supposons que vous avez une disposition de la table comme ce qui suit:Comment pourriez-vous résoudre ce problème SQL délicat?

couses:

id (INT), 
courseName (VARCHAR) 

instructeurs:

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

Créer une requête qui imprimera les tous les cours et si un instructeur est présent afficher son nom, si deux instructeurs sont présents, imprimer leurs noms sur la rangée dans l'ordre de tri, si plus de deux instructeurs sont présents à la place de l'affichage des noms des instructeurs "comité".

Par exemple votre sortie ressemblerait à quelque chose comme ça

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

Note: Tiré d'un questionnaire sur TheDailyWtf. Pas une question de devoirs.

+0

je pourrais le faire assez facile dans T-SQL avec un cas dans la sélection, mais je ne sais pas si MySQL prend en charge que ... –

+0

Je préfère voir les résultats cracher dans deux colonnes seulement CourseID et Instructor (s), et s'il y en a deux, il suffit de les afficher en virgule délimitée. C'est juste ma préférence cependant. – TheTXI

+0

excusez-moi, pourquoi est-il en baisse? C'est une véritable question de programmation, je ne pouvais pas comprendre comment le faire moi-même donc je l'ai posté ici –

Répondre

3

Dans SQL Anywhere, voici comment vous pourriez le faire :

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 

Notez que cette option sélectionne les Profs de 'que la liste des professeurs (comme indiqué dans la question) comme une seule colonne.

Je ne suis pas assez familier avec MySQL pour savoir s'il y a un équivalent à la fonction list().

7

Oui, oui, logique métier, etc. C'est un jeu, pas votre patron qui vous demande de le faire.

Dans 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

ne peut pas être traduit en mysql –

1

Ce que vous cherchez est un rapport "Tableau croisé dynamique" ou "Cross-tab". Ils sont disponibles en utilisant SQL normal:

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

Il y a ici des questions susceptibles d'autres sur SO avec plus d'informations aussi bien. Vérifiez les informations ici, qui montre comment vous pouvez le faire dans SQL, ou dans la logique de l'application (par requêtes successives):

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

+0

J'aime comment votre réponse (liée à l'article TheDailyWTF lié par l'asker de question) est comme le dernier ensemble de réponses (c.-à-d., «je le rechercherais en ligne, voici quelques liens potentiellement pertinents»). – JeeBee

+0

@RichB: Je suppose que nos modifications sont entrées en collision et que vous ne vouliez pas supprimer ce dernier lien. N'hésitez pas à modifier à nouveau si je me trompe, ou à enlever la signature ... –

+0

@JeeBee - Que puis-je dire? Je suis trop paresseux pour trouver et copier le code, mais je ne veux pas qu'ils soient non plus les mains vides. –

1

Pas la meilleure requête dans le monde, mais dans toute sa laideur, je l'aime bien. Plus précisément, j'aime le fait que vous ne devez pas traiter avec des déclarations multiples de cas, qui peut être une douleur si vous avez de nombreux domaines sur lesquels vous devez appliquer le cas:

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

Je pense que cela travailler, mais je ne l'ai pas encore testé. Ce n'est pas très évolutif si vous décidez que vous voulez commencer à montrer 3 instructeurs ou 4 ou plus bien.

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

Encore une autre alternative.Note:

1- Je ne crois pas que les solutions présentées jusqu'ici soient portables entre les dialectes SQL. Si un 4ème nombre de colonnes (*) était autorisé, je crois que la solution suivante pourrait être assez portable car elle utilise principalement le "SQL standard". Cependant, je n'ai testé que sur SQLite3.

2- Je me conforme intentionnellement à vos spécifications en reproduisant la faute de frappe de la table des cuisines. [Je suppose que ce devait être des cours au lieu de 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 
Questions connexes