sql >> データベース >  >> RDS >> Sqlserver

SQL - 別のテーブルで合計値を複数の行に分割する必要がある

    次のように実行できます。このクエリは、最初に最大収容人数の教室を設定します:

    DECLARE @School TABLE (School_Id INT,Course_Id 
        VARCHAR(50), Total_Students INT)
    DECLARE @Class TABLE (School_Id INT,Course_Id 
        VARCHAR(50), Class_ID VARCHAR(50), Capacity INT)
    INSERT @School VALUES 
       (1,         'Acct101'        ,150),
       (1,         'Acct102'        ,100),
       (2,         'Acct101'        ,110),
       (2,         'Acct102'        ,130)
    INSERT @Class VALUES 
       (1,         'Acct101'     ,'A1'       ,65),
       (1,         'Acct101'     ,'A2'       ,50),
       (1,         'Acct101'     ,'A3'       ,70),
       (1,         'Acct102'     ,'Ab1'      ,100),
       (1,         'Acct102'     ,'Ab2'      ,100),
       (2,         'Acct101'     ,'B1'       ,80),
       (2,         'Acct101'     ,'B2'       ,90)
    
    ;WITH y AS (
    SELECT  a.*,
            ROW_NUMBER() OVER 
                (PARTITION BY a.School_ID, a.Course_ID ORDER BY a.Capacity DESC) 
                CapacitiyOrderPerSchoolAndCourse,
            SUM(a.Capacity) OVER 
                (PARTITION BY a.School_ID, a.Course_ID) 
                TotalCapacityForSchoolAndCourse,
            b.Total_Students TotalParticipants
    FROM    @Class a
    JOIN    @School b ON 
            b.School_Id = a.School_Id
            AND b.Course_Id = a.Course_Id
    ), z AS(
    SELECT  x.School_Id, 
            x.Course_Id, 
            y.TotalCapacityForSchoolAndCourse, 
            y.TotalParticipants,
            CASE WHEN y.TotalParticipants < SUM(x.Capacity) THEN 
                    y.TotalParticipants
                ELSE 
                    SUM(x.Capacity) 
                END NumberOfStudentsInClasses,
            MIN(y.Capacity) ClassCapacity,
            y.Class_ID ClassName,
            MIN(y.Capacity) - 
            CASE WHEN y.TotalParticipants - SUM(x.Capacity) < 0 THEN 
                   ABS(y.TotalParticipants - SUM(x.Capacity))
                ELSE
                   0
                END StudentsInClass
    FROM    y
    JOIN    y x ON x.School_Id = y.School_Id 
            AND x.Course_Id = y.Course_Id 
            AND x.CapacitiyOrderPerSchoolAndCourse 
                    <= y.CapacitiyOrderPerSchoolAndCourse
    GROUP   BY x.School_Id, 
            x.Course_Id, 
            y.CapacitiyOrderPerSchoolAndCourse, 
            y.Class_ID, 
            y.TotalCapacityForSchoolAndCourse, 
            y.TotalParticipants
    )
    
    SELECT  
            z.School_Id, 
            z.Course_Id, 
            z.TotalCapacityForSchoolAndCourse, 
            z.TotalParticipants,
            z.ClassName,
            z.ClassCapacity,
            CASE WHEN StudentsInClass < 0 THEN 
                    0 
                ELSE 
                    StudentsInClass 
                END StudentsInClass
    FROM    z
    

    各教室に一定数の生徒を配置したい場合は、次のようにします (定員に応じて各教室に多数の生徒を割り当てます):

    ;WITH y AS (
    SELECT  a.*,
            SUM(a.Capacity) OVER 
                (PARTITION BY a.School_ID, a.Course_ID) 
                AS TotalCapacityForSchoolAndCourse,
            b.Total_Students TotalParticipants
    FROM    @Class a
    JOIN    @School b ON 
            b.School_Id = a.School_Id
            AND b.Course_Id = a.Course_Id
    ), z AS(
    SELECT  y.School_Id, 
            y.Course_Id, 
            y.TotalCapacityForSchoolAndCourse, 
            y.TotalParticipants,
            MIN(y.Capacity) ClassCapacity,
            y.Class_ID,
            MIN(y.Capacity) * 1.0 / y.TotalCapacityForSchoolAndCourse 
                AS PercentOfCapacity,
            ROUND(
                MIN(y.Capacity) * 1.0 / y.TotalCapacityForSchoolAndCourse 
                    * TotalParticipants
                , 0, 0) 
                AS NumberOfStudents
    FROM    y
    GROUP   BY y.School_Id, 
            y.Course_Id, 
            y.Class_ID, 
            y.TotalCapacityForSchoolAndCourse, 
            y.TotalParticipants
    )
    , i AS(
    SELECT  
            z.School_Id, 
            z.Course_Id, 
            z.TotalCapacityForSchoolAndCourse, 
            z.TotalParticipants,
            z.Class_ID,
            z.ClassCapacity,
            PercentOfCapacity,
            NumberOfStudents,
            SUM(NumberOfStudents) OVER 
                (PARTITION BY z.School_Id, z.Course_Id) 
                AS SumNumberOfStudents,
            ROW_NUMBER() OVER 
                (PARTITION BY z.School_Id, z.Course_Id 
                    ORDER BY NumberOfStudents) 
                AS ClassWithSmallestCapacity
    FROM    z
    ), j AS(
    SELECT  i.School_Id, 
            i.Course_Id, 
            i.TotalCapacityForSchoolAndCourse, 
            i.TotalParticipants,
            i.Class_ID,
            i.ClassCapacity,
            i.PercentOfCapacity,
            i.NumberOfStudents,
            i.NumberOfStudents +
            CASE WHEN ClassWithSmallestCapacity = 1 THEN 
                    TotalParticipants - SumNumberOfStudents 
                ELSE 0 
                END AS NumberOfStudents2
    FROM    i
    )
    
    SELECT  *
    FROM    j
    


    1. mysql integerフィールドに格納されている場合、数値がゼロで始まることを許可します

    2. SQL Server での int 値の読み取りとインクリメント

    3. OUTER APPLY クエリで varchar を XML にキャストする方法

    4. SQLでほぼ同じアイテムを組み合わせる方法は?