Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

SQL — muszę podzielić całkowitą wartość na wiele wierszy w innej tabeli

Możesz to zrobić w ten sposób, to zapytanie najpierw wypełnia klasy o największej pojemności:

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

Jeśli chcesz, aby każda klasa miała pewną liczbę uczniów, możesz to zrobić w ten sposób (przydziela liczbę uczniów do każdej klasy zgodnie z jej pojemnością):

;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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Port 1433 zapory nie otwiera się

  2. 5 sztuczek zapewniających najwyższą wydajność SQL Server

  3. Entity Framework 4 Code First — zapobieganie upuszczaniu/utworzeniu bazy danych

  4. Konwertuj wiersze na kolumny za pomocą „Pivot” w SQL Server

  5. Jak skutecznie modelować dziedziczenie w bazie danych?