2012-11-19 4 views
0

J'ai une table comme suitrequête SQL pour trouver le groupe

studentID Subject 
    1  Sub1 
    2  Sub1 
    3  Sub1 
    4  Sub1 
    1  Sub2 
    2  Sub2 
    4  Sub2 
    1  Sub3 
    3  Sub3 
    4  Sub3 

J'ai besoin de regrouper les étudiants qui a le même ensemble de Subjects.Just ont besoin d'un donner un identifiant de groupe unique aux étudiants avec un même ensemble de sujets .

donc ici id étudiant (1) et (4) va se dire groupe id = 1

id étudiant 2 - id groupe = 2 (personne d'autre n'a que des sous 1 et sous 2)

étudiant id 3 - id = groupe 3

le résultat devrait être comme

studentid groupid 
    1  1 
    4  1 
    2  2 
    3  3 

J'ai écrit un sqlquery qui utilise FORXML pour regrouper tous les sujets d'un étudiant à une seule colonne puis utilisez un groupe b y sur cette colonne et ensuite leur associer un rang. Existe-t-il une meilleure façon de le faire?

+0

Bonne question, ce n'est pas facile dans SQL. Créer une description de groupe en utilisant 'for xml' semble être une astuce pour résoudre ce problème. – Andomar

+0

Je pense que c'est une bonne façon de résoudre ce problème avec le regroupement par Sub concaténé. Vous devez vérifier que vous avez l'ordre correct des sujets dans la chaîne concaténée, bien que –

Répondre

1

Voici une approche.

Pour chaque étudiant, trouvez tous les autres étudiants qui ont la même série de cours. Vous pouvez le faire en utilisant les règles suivantes. Deux étudiants ont les mêmes cours quand (1) ils ont chacun le même nombre de cours; (2) le nombre de cours qu'ils ont en commun est le même que le nombre de cours.

L'implémentation utilise des fonctions de classement pour trouver le nombre de cours et une jointure/groupe pour compter le nombre en commun pour deux étudiants différents. Après cela, l'identifiant de groupe est simplement l'identifiant d'étudiant minimum, parmi les paires dans cette table.

select s1.StudentId, MIN(SameAsStudentId) as groupid 
from (select s1.StudentId as StudentId, s2.StudentId as SameAsStudentId 
     from (select ss.*, COUNT(*) over (studentId) as NumSubjects 
      from ss 
      ) s1 join 
      (select ss.*, COUNT(*) over (studentId) as NumSubjects 
      from ss 
      ) s2 
      where s1.Subject = s2.Subject 
     group by s1.StudentId, s2.StudentId 
     having s1.NumSubjects = s2.NumSubjects and 
      COUNT(*) = s1.NumSubjects 
    ) t 
group by StudentId 

Si vous voulez groupId qui n'a pas de « trous », vous pouvez envelopper une requête externe qui utilise dense_rank pour affecter l'ID du groupe.

0

Une façon de gérer cela est de créer un masque de bits pour les sujets. Attribuez d'abord deux puissances distinctes et arbitraires de deux à chacun des sujets:

Subject Value 
Sub1   1 
Sub2   2 
Sub3   4 

Vous pouvez maintenant additionner les valeurs de chaque sujet. Chaque combinaison de sujets aura une valeur unique. Il y a une mise en garde, en ce que si le nombre de sujets est trop grand, vous pourriez obtenir un débordement numérique.

Vous pouvez même le faire en une seule requête:

Select StudentID, sum(Subject_Value) 
from Student_Subjects ss join 
    (select distinct subject, 
         power(2,dense_rank() 
           over (order by subject)-1) as Subject_Value 
     from Student_Subjects) sv 
    on ss.subject = sv.subject 
group by StudentID 
Questions connexes