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

私が扱っているテーブルには 1,000 万行ありますが、一意の行セットは 200 しかありません。select ステートメントは StudentId を無視して、動的に生成された ClassId に置き換えることができます。次に、この select ステートメントを使用して、一意の行セットをクラス テーブルに挿入できます。

4

2 に答える 2

0

そこで、あなたの一番上のテーブルを取得して、教室のリストを生成する次の動的クエリを作成しました。これにより、2 番目のテーブルとして正確な出力が得られます。

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 に答える