SQL Server:计算派生表中的百分比

时间:2018-07-29 14:59:26

标签: sql sql-server

我正在尝试使用3个表并创建一个派生表,以将一些数据显示在一起,以显示完成百分比。

我正在使用的3个表是StudentTestsResults。我正在尝试将3个课程合并在一起,并创建一个派生表,其中以完成的测试百分比显示学生及其取得的进步。

作为一个例子,假设我要跟踪的3个学生都被分配了3个测试(在一个有数百个表的表中),我想看看他们走了多远。如果他们完成了所有3个测试,则派生表应存储100%的值。

StudentID  SName
-----------------
1          Ken
2          Tom
3          Bob

TestID  TName 
----------------
11      Test 101
22      Test 102
33      Test 103

ResultsID  TestID  StudentID   Passed
--------------------------------------
  1          11      Tom          0
  2          11      Bob          1
  3          22      Bob          1
  4          33      Bob          1

派生表:

StudentID  SName %Completed
---------------------------
1          Ken      0%
2          Tom      0%
3          Bob    100%

我尝试了许多不同的方法,甚至不知道显示哪个方法,因为我觉得所有尝试都是完全错误的。有任何想法吗?抱歉,如果格式不好,这是我在这里的第一篇文章:)

谢谢!

3 个答案:

答案 0 :(得分:0)

这似乎像joingroup by一样:

select s.StudentID, s.SName,
       sum(case when r.passed = 1 then 1.0 else 0 end) / t.cnt as ratio
from students s left join
     results r
     on s.studentid = r.studentid cross join
     (select count(*) as cnt
      from tests
     ) t
group by s.StudentID, s.SName, t.cnt;

答案 1 :(得分:0)

让所有可能的学生与测验组合。
可以交叉加入学生应通过的测试的子查询。

然后,可以将学生/考试的所有可能组合与实际结果结合在一起。

在那之后,这是一个平均的简单GROUP BY。

select 
 stu.StudentID, 
 stu.SName, 
 concat(AVG(coalesce(res.Passed,0)*100),'%') as [%Completed]
from Students as stu
cross join (
    select TestID, TName 
    from Tests 
    where TestID in (11,22,33)
) as tst
left join Results as res on (res.StudentID = stu.StudentID and res.TestID = tst.TestID)
group by stu.StudentID, stu.SName

示例代码段

-- Sample data
-- Using table variables for demonstration
declare @Students table (StudentID int identity(1,1) primary key, SName varchar(30));
insert into @Students (Sname) values 
('Ken'),
('Tom'),
('Bob'),
('Jane');
declare @Tests table (TestID int primary key, TName varchar(30));
insert into @Tests (TestID, TName) values 
(11,'Test 101'),
(22,'Test 102'),
(33,'Test 103');
declare @Results table (ResultsID int identity(1,1) primary key, TestID int, StudentID int, Passed bit);
insert into @Results (TestID, StudentID, Passed) values
(11,2,0),
(11,3,1),(22,3,1),(33,3,1),
(11,4,1);

-- Query
select 
 stu.StudentID, 
 stu.SName, 
 concat(AVG(coalesce(res.Passed,0)*100),'%') as [%Completed]
from @Students as stu
cross join (
    select TestID, TName 
    from @Tests 
    where TestID in (11,22,33)
) as tst
left join @Results as res on (res.StudentID = stu.StudentID and res.TestID = tst.TestID)
group by stu.StudentID, stu.SName;

结果:

StudentID   SName   %Completed
---------   -----   ----------
        1   Ken     0%
        2   Tom     0%
        3   Bob     100%
        4   Jane    33%

答案 2 :(得分:0)

从数据中,我们看不到Ken已被分配给这3个测试,因此我们必须假定所有跟踪的学生都已分配给所有跟踪的测试。

这就是我要做的:

  1. 构建一组所有跟踪的学生和测试的组合(CROSS JOIN并具有2个WHERE条件)
  2. 使用LEFT OUTER JOIN确定结果(将NULL替换为0)
  3. 在我AVG学生的时候计算GROUP BY结果(广播到一个数字)

这可以用单个SELECT语句编写:

SELECT s.StudentID, s.SName, AVG(CAST(ISNULL(r.Passed, 0) as float)) AS Completed
FROM Students s CROSS JOIN Tests t
  LEFT OUTER JOIN Results r ON t.TestID = r.TestID AND s.StudentID = r.StudentID
WHERE s.StudentID IN (1, 2, 3)
  AND t.TestID IN (11, 22, 33)
GROUP BY s.StudentID, s.SName

Completed值的格式(百分比)应在客户端应用程序中完成。