0

我有一张看起来像这样的桌子

StudentId  Subject   Section
1           2          AM
1           3          AM
1           1          AM

2           2          AM
2           3          AM
2           1          AM

3           4          AM
3           2          PM
3           3          PM

4           2          PM
4           3          PM

我想从此表中获取唯一的行集来安排教室。具有完全相同科目和部门的学生可以去同一个教室。因此,根据上面的示例数据,学生 1 和 2 将去同一个教室,但学生 3 和 4 不会去,因为他们有不同的科目和/或部分。

学生 3 和 4 也不能去同一个班级,尽管学生 4 的学科/部分组合是学生 3 的子集(但不完全相同)。

换句话说,为了在同一个教室里,学生必须拥有完全相同的科目、相同数量的科目和相同的部分。上述示例数据的输出应如下所示。

ClassId   Subject   Section
1           2        AM
1           3        AM
1           1        AM

2           4        AM
2           2        PM
2           3        PM

3           2        PM
3           3        PM

我正在处理的表有 1000 万行,但只有 200 个唯一行集。select 语句可以忽略 StudentId,并可以将其替换为动态生成的 ClassId。然后我可以使用这个 select 语句将唯一的行集插入到类表中。

4

2 回答 2

0

所以我拿了你的表,写了下面的动态查询来生成一个教室列表。这将为您提供作为第二个表的确切输出。

declare @subjects varchar(max)
set nocount on
select
    @subjects = coalesce(@subjects,'') + 
          quotename(cast(subject as varchar(25))) + ','
from
    [student]
group by
    Subject

set @subjects = substring(@subjects,0,len(@subjects))
declare @dyn_sql varchar(max)

set @dyn_sql = 
'
select
    class_room,
    subject,
    section
from
    (
select
    row_number() over (order by '+@subjects+') as class_room,
    '+@subjects+',
    count(distinct studentid) as total_students
from
    (
    SELECT 
        studentId,
        cast(subject as varchar(25)) as subject,
        section
    FROM [student]
    ) as d1
pivot (max(section) for subject in ('+@subjects+')) as d2
group by
'+@subjects + '
) as d1
unpivot(section for subject in  ('+@subjects+')) as d2
'

exec (@dyn_sql)
print (@dyn_sql)
于 2013-04-10T19:12:33.207 回答
0

这具有填充类表和studentID和classID之间的连接表的查询......

(注意:首先运行注释掉的逻辑来填充临时表)

/*
Create  Table testData (StudentID Int, [Subject] Int, Section Varchar(2))

Insert  testData
Select  1,2,'AM'
Union   All
Select  1,3,'AM'
Union   All
Select  1,1,'AM'
Union   All
Select  2,2,'AM'
Union   All
Select  2,3,'AM'
Union   All
Select  2,1,'AM'
Union   All
Select  3,4,'AM'
Union   All
Select  3,2,'PM'
Union   All
Select  3,3,'PM'
Union   All
Select  4,2,'PM'
Union   All
Select  4,3,'PM';
*/

--      Get class info
If      Object_ID('tempdb..#classes') Is Not Null Drop Table #classes;

With    studentClasses As
(
        Select  t.StudentID,
                Replace((   Select Convert(Varchar(10),[Subject])+'_'+Section As 'data()'
                            From    #testData t2
                            Where   t.studentID = t2.studentID
                            Order   By Section,[Subject]
                            For     Xml Path('X')), ' ', ',') As classes
        From    #testData t
        Group   By t.studentID
),      classIDs As
(
        Select  Row_Number() Over (Order By classes) As classID,
                Convert(XML,classes) As classes
        From   (Select  Distinct classes
                From    studentClasses) sc
),      breakOutClasses As
(
        Select  Row_Number() Over (Partition By cID,classID Order By classID) As nID,
                n.cID,
                n.classID,
                t.split
        From   (Select  Row_Number() Over (Partition By classID Order By classID) As cID,
                        classID,
                        Convert(Xml,'<X>'+Replace(t2.split,'_','</X><X>')+'</X>') As firstBreak
                From    classIDs c
                Cross   Apply  (Select  colData.D.value('.','Varchar(50)') As split
                                From    c.classes.nodes('X') As colData(D)) t2) n
        Cross   Apply  (Select  colData.D.value('.','Varchar(50)') As split
                        From    n.firstBreak.nodes('X') As colData(D)) As t                 
)
Select  b1.classID, b1.split As [Subject], b2.split As Section Into #classes
From    breakOutClasses b1
Join    breakOutClasses b2
        On  b1.classID = b2.classID
        And b1.cID = b2.cID
        And b1.nID = 1
        And b2.nID = 2
Order   By classID, Section, [Subject];


If      Object_ID('tempdb..#studentClassID') Is Not Null Drop Table #studentClassID;

With    students As
(
        Select  t.StudentID,
                Replace((   Select Convert(Varchar(10),[Subject])+'_'+Section As 'data()'
                            From    #testData t2
                            Where   t.studentID = t2.studentID
                            Order   By Section,[Subject]
                            For     Xml Path('')), ' ', ',') As classes
        From    #testData t
        Group   By t.studentID
),      classes As
(
        Select  t.classID,
                Replace((   Select Convert(Varchar(10),[Subject])+'_'+Section As 'data()'
                            From    #classes t2
                            Where   t.classID = t2.classID
                            Order   By Section,[Subject]
                            For     Xml Path('')), ' ', ',') As classes
        From    #classes t
        Group   By t.classID
)
Select  c.classID, s.studentID Into #studentClassID
From    classes c
Join    students s
        On  c.classes = s.classes;


Select  *
From    #classes;

Select  *
From    #studentClassID;
于 2013-04-10T19:16:27.190 回答