将记录同等分组

时间:2013-05-15 19:55:04

标签: sql postgresql

我想要建立一个计划程序(我想写sql来做它然后我将构建一个php站点来执行它)。对于初学者,我想把我在学校的学生分给老师。我需要他们在性别平衡,意味着相同或在每个班级中不超过另一个性别的30%。

所以我有一个学生表,所有年级1-5级和一个教师表,其中一个字段指定他们教授的等级。然后我有一个课程表,其中包含每位老师教授的课程,其中包含一个具有班级大小限制的字段(仅允许18名学生等)以及教授该课程的教师ID。

Student Table Example:

Student_ID  Grade_Level
253486           1
365896           2
485785           3
968654           4
154278           5



Teacher Table Example:

Teacher_ID  Grade Taught
253              1
584              2
985              3
647              4
254              5

Course Table Example:

Course_ID   Class_Limit Teacher_ID
5007010      15            253
5007011      15            584
5007012      18            985
5007013      18            647
5007014      10            254

我希望最终结果是将记录转储到一个包含三个字段的表中:教师ID,课程ID和学生ID。

一旦我理解了这一点,我想最终建立起来并添加更多方法来分解它们。

如果你想知道为什么我要这样做是因为我们当前的调度程序不支持这种调度,而且我不确定它们何时会添加它。但即使只是这个简单的步骤也会节省大量的时间。

感谢任何意见或帮助。

2 个答案:

答案 0 :(得分:1)

以下是您可以采取的方法。

关键的想法是计算每个班级中男女学生的数量,然后分配它们。如果我们有信息,分配很简单。所以,假设我们拥有它:

with magictable (
      <subquery here is nummale and numfemale in each class
     ),
     classinfo (
      select mt.*,
             sum(nummales) over (partition by grade) - 1 as endrange_male,
             sum(nummales) over (partition by grade) - nummales as startrange_male,
             sum(numfemales) over (partition by grade) - 1 as endrange_female,
             sum(numfemales) over (partition by grade) - numfemales as startrange_female
      from magictable mt
     )
select
from (select s.*,
             ROW_NUMBER() over (partition by grade, gender order by student_id) as seqnum
      from student s
     ) s join
     classinfo ci
     on (s.gender = 'M' and s.seqnum between startrange_male and endrange_male) or
        (s.gender = 'F' and s.seqnum between startrange_female and endrange_female)

因此,这会将分配信息转换为计算每个班级中男性和女性的数量。您可能有其他方法可以实现此目的,因此我将在此处给出一个近似的答案。

您可以计算每个年级的学生人数,男性人数和女性人数。通过从总容量中减去实际学生数来计算“超额”学生的数量。这给出了每个类的实际大小。然后按男/女比例划分。

以下查询显示了如何执行此操作:

  select c.*,
         (c.class_limit - ((csum.maxcapacity - ssum.numstudents)/csum.numcourses)) as actsize,
         (c.class_limit - ((csum.maxcapacity - ssum.numstudents)/csum.numcourses)) * (NumMales / NumStudents) as actMales,
         (c.class_limit - ((csum.maxcapacity - ssum.numstudents)/csum.numcourses)) * (NumFemales / NumStudents) as actFemales
  from course c join
       teacher t
       on c.teacher_id = t.teacher_id
       (select grade, count(*) as numcourses, SUM(class_limit) as maxcapacity
        from course c join
             teacher t
             on c.teacher_id = t.teacher_id
        group by grade
       ) csum
       on t.grade = csum.grade join
       (select grade, sum(case when gender = 'M' then 1 else 0 end) as NumMales,
               sum(case when gender = 'F' then 1 else 0 end) as NumFemales,
               count(*) as NumStudents
        from s
        group by grade
       ) ssum
       on t.grade = ssum.grade;

问题是,这是一个近似值,因为它处理的是分数学生。而且,唉,真正的学生只有非分数的大小。

有一个真正的解决方案来计算离散尺寸。相反,我只是将NumMales和NumFemales轮到下一个整数并将其用于估算。这可能足以满足您的目的。

并且,此解决方案中的代码是说明解决方案。它可能有句法问题。

答案 1 :(得分:0)

遵循规范化原则并使用您现有的架构,我猜你所要求的并不是你想要的

我不明白你为什么需要在表格中使用teacherID,因为你已经拥有一个带有TeacherID FK的课程表。

我认为你需要的是StudentCourses表。这个表有两个字段,studentID和courseID(courseID是FK到Course表,studentID到Student表。有两部分学生ID和CourseID的复合PK。

示例数据看起来像

      StudentRegistrations

    CourseID            StudentID
   5007010                26352
   5007010                26732
   6003790                26352

除非我完全误解,否则你只是要求我们写一个SP来随机将学生放入课程中。不过,我上面提出的观点仍然有效。