0

我有三个表:成绩、作业、用户。我希望能够找到用户已经完成和尚未完成的任务。我知道我们在这里使用 OUTER 连接,但我似乎无法获得正确的 SQL 来复制我想要的内容。在我的表格中,1 名学生已完成 1 项作业(显示 1、3、1 名学生已完成 2 项作业,1 名学生已完成 3 项作业,请在下方发布完整表格

assignment table:

assignmentID |  assignmentType | totalScore |
-------------|-----------------|------------|
      1      |   Assignment    |    100     |
      2      |   Assignment    |    100     |
      3      |   Assignment    |    100     |
      4      |   Test          |    200     |

grade table:

gradeID  |  studentID  |  assignmentID  |  grade  |
---------|-------------|----------------|---------|
   1     |      3      |       1        |    100  | 
   2     |      3      |       2        |    100  |                
   3     |      3      |       3        |    100  |                
   4     |      2      |       1        |    100  |                
   5     |      2      |       2        |    100  |                
   6     |      1      |       1        |    100  | 

student table:

studentID  | studentName |
-----------|-------------|
     1     |     John    |     
     2     |     Jane    |
     3     |     Joe     |

因此,在上述场景中,John 将完成 1 个作业,3 个未完成,Jane 将完成 2 个作业,2 个未完成作业,而 Joe 将完成 3 个作业,1 个未完成作业。

希望输出为:

studentID | achievementID | grade |
----------|---------------|-------|
    1     |       1       |  100  |
    1     |       2       |  NULL |
    1     |       3       |  NULL |
    1     |       4       |  NULL |
    2     |       1       |  100  |
    2     |       2       |  100  |
    2     |       3       |  NULL |
    2     |       4       |  NULL |
    3     |       1       |  100  |
    3     |       2       |  100  |
    3     |       3       |  100  |
    3     |       4       |  NULL |

任何帮助是极大的赞赏。

4

4 回答 4

2

这是实现它的一种方法。您可以full outer join在表之间执行 a studentassignment因为您希望它们之间的所有组合都包含在结果集中。在包含学生和作业的所有组合的派生输出表上,LEFT OUTER JOIN在表中添加一个成绩以获取成绩结果,

单击此处查看 SQL Fiddle 中的演示。

脚本

CREATE TABLE assignment
(
    assignmentid    INT         NOT NULL
  , assignmenttype  VARCHAR(20) NOT NULL
  , totalscore      INT         NOT NULL
);

CREATE TABLE grade
(
    gradeid         INT NOT NULL
  , studentid       INT NOT NULL
  , assignmentid    INT NOT NULL
  , grade           INT NOT NULL
);

CREATE TABLE student
(
    studentid   INT         NOT NULL
  , studentname VARCHAR(20) NOT NULL
);

INSERT INTO assignment (assignmentid, assignmenttype, totalscore) VALUES
    (1, 'Assignment', 100),
    (2, 'Assignment', 100),
    (3, 'Assignment', 100),
    (4, 'Test', 200);

INSERT INTO grade (gradeid, studentid, assignmentid, grade) VALUES
    (1, 3, 1, 100),
    (2, 3, 2, 100),
    (3, 3, 3, 100),
    (4, 2, 1, 100),
    (5, 2, 2, 100),
    (6, 1, 1, 100);

INSERT INTO student (studentid, studentname) VALUES
    (1, 'John'),
    (2, 'Jane'),
    (3, 'Joe'),
    (4, 'Jill');

SELECT  sa.studentid
    ,   sa.studentname
    ,   sa.assignmentid
    ,   g.grade
FROM
(
        SELECT  s.studentid
            ,   s.studentname
            ,   a.assignmentid 
        FROM    student     s
            ,   assignment  a
)               sa 
LEFT OUTER JOIN grade g
ON              sa.studentid    = g.studentid
AND             sa.assignmentid = g.assignmentid
ORDER BY        sa.studentid
            ,   sa.assignmentid;

输出

STUDENTID STUDENTNAME ASSIGNMENTID GRADE
--------- ----------- ------------ -----
     1    John              1       100
     1    John              2       
     1    John              3 
     1    John              4 
     2    Jane              1       100
     2    Jane              2       100
     2    Jane              3 
     2    Jane              4 
     3    Joe               1       100
     3    Joe               2       100
     3    Joe               3       100
     3    Joe               4 
     4    Jill              1 
     4    Jill              2 
     4    Jill              3 
     4    Jill              4 
于 2012-04-30T00:44:25.687 回答
2

试试这个:http ://www.sqlfiddle.com/#!2/23408/15

select s.studentID, s.studentName,


    count(g.assignmentID) as completed,
    count(a.assignmentID) - count(g.assignmentID) as incomplete,

    count(a.assignmentID) as total

from student s
cross join assignment a

left join grade g 
on g.studentId = s.studentId
and g.assignmentID = a.assignmentID

group by s.studentId

输出:

STUDENTID       STUDENTNAME     COMPLETED       INCOMPLETE      TOTAL
1               John            1               3               4
2               Jane            2               2               4
3               Joe             3               1               4

样本数据:

CREATE TABLE assignment
    (assignmentID int, assignmentType varchar(10), totalScore int);

INSERT INTO assignment
    (assignmentID, assignmentType, totalScore)
VALUES
    (1, 'Assignment', 100),
    (2, 'Assignment', 100),
    (3, 'Assignment', 100),
    (4, 'Test', 200);



CREATE TABLE student
    (studentID int, studentName varchar(4));

INSERT INTO student
    (studentID, studentName)
VALUES
    (1, 'John'),
    (2, 'Jane'),
    (3, 'Joe');

CREATE TABLE grade
    (gradeID int, studentID int, assignmentID int, grade int);

INSERT INTO grade
    (gradeID, studentID, assignmentID, grade)
VALUES
    (1, 3, 1, 100),
    (2, 3, 2, 100),
    (3, 3, 3, 100),
    (4, 2, 1, 100),
    (5, 2, 2, 100),
    (6, 1, 1, 100);
于 2012-04-30T00:48:09.593 回答
2

另一种方法可能更快,总分配的计算只完成一次:

http://www.sqlfiddle.com/#!2/23408/17

select s.studentID, s.studentName,


    count(g.assignmentID) as completed,
    ta.total - count(g.assignmentID) as incomplete,

    ta.total

from student s
cross join (select count(*) as total from assignment) as ta

left join grade g 
on g.studentId = s.studentId

group by s.studentId

但是,这需要成绩的 assignmentID 和 assignment 的 assignmentID 之间的外键保持一致,因为此查询盲目地计算学生的作业

于 2012-04-30T00:54:20.637 回答
2

您的新要求:http ://www.sqlfiddle.com/#!2/23408/23

select s.studentID, 

    a.assignmentID as achievementID,
    g.grade

from student s
cross join assignment a

left join grade g 
on g.studentId = s.studentId
and g.assignmentID = a.assignmentID

order by s.studentID, achievementID

输出:

STUDENTID    ACHIEVEMENTID    GRADE
1            1                100
1            2    
1            3    
1            4    
2            1                100
2            2                100
2            3    
2            4    
3            1                100
3            2                100
3            3                100
3            4    

sqlfiddle 不会在其输出中将 NULL 显示为 NULL。尽管如此,上述空等级的基础空值是 NULL


您也可以使用表格逗号表格,而不是使用CROSS JOIN;但这通常是不受欢迎的。使用逗号表很容易提交无意的笛卡尔积,想象一下使用逗号表的方法在三个或更多表上会产生多少行。这就是为什么在 SQL 中引入 JOIN (INNER,LEFT,CROSS,FULL,NATURAL) 关键字以使代码意图更加清晰

http://www.sqlfiddle.com/#!2/23408/37

select s.studentID, 

    a.assignmentID as achievementID,
    g.grade

from (student s, assignment a)

left join grade g 
on g.studentId = s.studentId
and g.assignmentID = a.assignmentID

order by s.studentID, achievementID

我宁愿使用 CROSS JOIN 关键字而不是使用表逗号表。CROSS JOIN 形式化了笛卡尔积的概念。JOIN 通常形式化了您想要在查询中实现的目标。对于逗号表,很难从查询中推断出您的表是否会以inner-join-y操作或left-join-y操作等结束。

于 2012-04-30T04:07:06.270 回答