【问题标题】:Sql Server - Join and group with table which has more recordsSql Server - 与具有更多记录的表连接和分组
【发布时间】:2020-11-10 15:01:11
【问题描述】:

我有以下 4 张桌子:

  • 用户
  • 学生
  • 部门
  • 标记

我正在尝试按 DepartmentId 获取学生总数和总分总和。例如,我的结果集应该是部门 ID 1 有 50 名学生,所有学生在跨部门的所有考试中获得的总分数为 1200。

当我需要部门总分时,下面的查询给出了正确的结果

SELECT DepartmentId, SUM([Value]) AS TotalMarks FROM [dbo].[Marks] M
WHERE CollegeId = 3
GROUP BY DepartmentId

当我只需要按部门划分的学生总数时,以下查询给出了正确的结果。

SELECT S.[DepartmentId], COUNT(U.[StudentId]) AS TotalStudents
FROM [dbo].User U
INNER JOIN dbo.[Student] S
ON U.[UserId] = S.[UserId]
INNER JOIN [dbo].Department D
ON D.[DepartmentId] = S.[DepartmentID]
WHERE D.[CollegeId] = 3 AND U.[IsFullTimeStudent] = 1
GROUP BY S.[DepartmentId]

现在,当我想使用以下查询在单个结果中按部门获取学生总数和总分数时,我遇到了问题。我的 Marks 表可以为单个用户包含多个记录,因此它会给出冗余结果。

   SELECT S.[DepartmentId], COUNT(U.[StudentId]) AS TotalStudents, SUM(M.[Value]) AS TotalMarks
   FROM [dbo].User U
   INNER JOIN dbo.[Student] S
   ON U.[UserId] = S.[UserId]
   INNER JOIN [dbo].Department D
   ON D.[DepartmentId] = S.[DepartmentID]
   INNER JOIN [dbo].[Marks] M
   ON D.[DepartmentId] = M.[DeprtmentId]
   WHERE D.[CollegeId] = 3 AND U.[IsFullTimeStudent] = 1
   GROUP BY S.[DepartmentId]

我的标记表有 UserId、DepartmentId、CollegeId、Value 字段。

例如:- 如果标记表中有 110 个 DepartmentId 1 条目和 1 个 FTE 学生的学生,那么在这种情况下,TotalUsers 我得到 110 个学生总数,尽管该部门只有 1 个学生,因为有 110 个条目我得到的分数是 110 名学生

有没有更简单的方法来解决这个问题?

【问题讨论】:

    标签: sql-server join


    【解决方案1】:

    一些示例数据和表定义会很有用。我发明了自己的示例数据,它应该几乎适合您的表定义。

    使用cross applyouter applydocumentationexamples)允许合并计数和求和结果。

    样本数据

    create table departments
    (
      departmentid int,
      departmentname nvarchar(20)
    );
    insert into departments (departmentid, departmentname) values
    (1000, 'Business Faculty'),
    (2000, 'Science Faculty' ),
    (3000, 'Maintenance'     );
    
    create table users
    (
      departmentid int,
      userid int,
      username nvarchar(10),
      isfulltimestudent bit
    );
    insert into users (departmentid, userid, username, isfulltimestudent) values
    (1000, 1, 'Alice',    1),
    (1000, 2, 'Bob',      0),
    (2000, 3, 'Clarence', 1),
    (2000, 4, 'Britt',    0);
    
    create table students
    (
      userid int,
      studentid int
    );
    insert into students (userid, studentid) values
    (1, 100),
    (2, 200),
    (3, 300);
    
    create table marks
    (
      departmentid int,
      userid int,
      mark int
    );
    insert into marks (departmentid, userid, mark) values
    (1000, 1, 15),
    (1000, 1,  8),
    (1000, 2, 13),
    (1000, 2, 12),
    (2000, 3, 10),
    (2000, 3,  7),
    (2000, 3, 15),
    (2000, 4, 10);
    

    解决方案

    select d.departmentname,
           ts.TotalStudents,
           tm.TotalMarks
    from departments d
    outer apply ( select count(1) as TotalStudents
                  from users u
                  where u.departmentid = d.departmentid
                    and u.isfulltimestudent = 1 ) ts
    outer apply ( select sum(m.mark) as TotalMarks
                  from marks m
                  where m.departmentid = d.departmentid ) tm;
    

    Fiddle 看看它的实际效果。


    应用解决方案

    Untested 合并来自您问题的查询的查询:

    SELECT d.DepartmentId,
           tm.TotalMarks,
           ts.TotalStudents
    FROM dbo.Department d
    OUTER APPLY ( SELECT SUM(m.[Value]) AS TotalMarks
                  FROM dbo.Marks m
                  WHERE m.DepartmentId = d.DepartmentId ) tm
    OUTER APPLY ( SELECT COUNT(u.StudentId) AS TotalStudents
                  FROM dbo.User u
                  JOIN dbo.Student s
                    ON u.UserId = s.UserId
                  WHERE u.IsFullTimeStudent = 1
                    AND s.DepartmentId = d.DepartmentId ) ts
    WHERE d.CollegeId = 3;
    

    【讨论】:

    • 谢谢 Sander,帮了大忙。
    猜你喜欢
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多