我是SQL新手。我有一个包含不同考试数据的数据库,例如:
Student Test Grade
--------------------
St1 T1 A
St2 T1 B
St3 T1 B
St1 T2 B
St2 T2 B
St3 T2 A
St1 T3 A
St2 T3 C
St3 T3 B
然后,我想使用测试(T1,T2和T3)作为列打印报告:
Student T1 T2 T3
----------------------
St1 A B A
St2 B B C
St3 B A B
我尝试了不同的东西,但我不知道如何制作这样的打印输出。任何帮助表示赞赏!
答案 0 :(得分:11)
使用:
SELECT t.student,
MAX(CASE WHEN t.test = 'T1' THEN t.grade END) AS T1,
MAX(CASE WHEN t.test = 'T2' THEN t.grade END) AS T2,
MAX(CASE WHEN t.test = 'T3' THEN t.grade END) AS T3
FROM TABLE t
GROUP BY t.student
答案 1 :(得分:1)
答案 2 :(得分:1)
我相信如果您要扩展此系统以包含更多信息,那么您可以从重新编写数据库中受益,我会像这样构建它:
表名 =粗体
列名 =斜体
<强>学生强>:
<强>测试强>:
测试成绩
这种结构基于一种称为数据库规范化的想法(如果你谷歌它,你会得到很多信息)。我将在下面给你一个部分摘要,但如果你要做很多SQL,你应该自己阅读:
首先要知道的是,主键只是一个唯一的标识符,它通常不是信息的一部分(但是,因为它是唯一的,每个数据必须具有不同的主键值)和外键是一种使用referencee的主键从另一个表中的行引用一个表中的行的方法:例如,每个等级中的外键 SID 根据其主键引用单个学生 SID
e.g。学生1有SID 1,他的所有测试在SID栏中都有1。同样适用于学生2,3,4等。
规范化的基本思想是,所有唯一数据仅存储一次,然后在使用它的其他地方引用(如果您看一下示例中键的结构,所有学生信息都存储在一个表,然后在他们的测试成绩中引用,而不是在每个年级中重复。)
要从这些表中检索您想要的内容,我会使用它(用PHP编写):
$sql = 'SELECT * FROM Tests ORDER BY TID';
$tempresult = mysql_query($sql);
while($temprow = mysql_fetch_array($tempresult)){
echo $temprow['TID'];
}
$sql = 'SELECT * FROM Students';
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)){
echo '\n'.$row['SID'];
$sql = 'SELECT * FROM Grades WHERE SID='.$row['SID'].' ORDER BY TID';
$result2 = mysql_query($sql);
while($row2 = mysql_fetch_array($result2)){
echo ' '.$rows['Grade'];
}
}
您可以在echo语句中为此添加格式,还可以打印您选择添加的任何额外信息。如果你有任何问题,请问他们。
编辑:我已经读过其他人了,并且同意他们的方法很可能是优越的,我唯一不确定的是数据透视表是否可以扩展以处理不同数量的测试,如果它可以(或你不需要),那么我建议他们的方法,否则我觉得这可能在你的应用程序中占有一席之地。
答案 3 :(得分:1)
有两种方法可以做到这一点,两者都是(在纯SQL而不是生成SQL命令的代码中)需要知道和修复列数。最直接的实现方式是:
SELECT eg.Student,
(SELECT Grade from ExamGrade eg1 WHERE eg1.Student = eg.Student AND Test = 'T1') AS T1
(SELECT Grade from ExamGrade eg2 WHERE eg2.Student = eg.Student AND Test = 'T2') AS T2
(SELECT Grade from ExamGrade eg3 WHERE eg3.Student = eg.Student AND Test = 'T3') AS T3
FROM ExamGrade eg
这几乎可以在包括SQLite在内的任何环境中使用,并且可以通过标量值函数GetTest()使其更加优雅,该函数将获取学生和测试编号并返回成绩。但是,无论如何,这既不是表现也不是封闭的改变;它将查询N次测试的N次平方时间,如果添加第4次测试,则必须更改此查询以将其包含在报告中。
如果Student和Test的组合是唯一的,并且您正在使用Pivot功能(显然SQLite没有)的数据库中工作,则可以使用几乎任何聚合器的Pivot查询(MAX / MIN)具有单个值的集合的/ AVG / SUM是该值)。以下适用于MSS2005:
SELECT Student, T1, T2, T3
FROM (Select Student, Test, Grade FROM ExamGrade) As SourceQuery
PIVOT (MAX(Grade) FOR Test IN (T1, T2, T3)) AS PivotTable
这将更高效,而且更优雅。列列表仍然无法动态确定AFAIK,但如果您从应用程序代码进行此查询,或使用MS SQL Server中的sp_executesql内置存储过程从另一个存储过程生成查询,则它们很容易生成功能
答案 4 :(得分:0)
试试这个
SELECT Student, MAX(CASE WHEN Test = 'T1' THEN Grade END) AS T1,
MAX(CASE WHEN Test = 'T2' THEN Grade END) AS T2,
MAX(CASE WHEN Test = 'T3' THEN Grade END) AS T3 FROM tablename GROUP BY Student
使用您的表名而不是“tablename”。
答案 5 :(得分:0)
我想在@OMG_Ponies的答案中添加一些解释,因为它对SQL no-super-users(比如我自己)很有用
让我们创建一个示例表并添加虚拟数据:
CREATE TABLE t (
t_ID integer primary key autoincrement not null,
student integer,
test text,
grade text
);
INSERT INTO t
(student, test, grade)
VALUES
('St1', 'T1', 'A'),
('St2', 'T1', 'B'),
('St3', 'T1', 'B'),
('St1', 'T2', 'B'),
('St2', 'T2', 'B'),
('St3', 'T2', 'A'),
('St1', 'T3', 'A'),
('St2', 'T3', 'C'),
('St3', 'T3', 'B');
所以我们有以下内容:
t_ID student test grade
-------------------------
1 St1 T1 A
2 St2 T1 B
3 St3 T1 B
4 St1 T2 B
5 St2 T2 B
6 St3 T2 A
7 St1 T3 A
8 St2 T3 C
9 St3 T3 B
使用语句case when ... then ... end
可以获得所需的列
SELECT
t_ID,
student,
(case when t.test = 'T1' then t.grade end) as T1,
(case when t.test = 'T2' then t.grade end) as T2,
(case when t.test = 'T3' then t.grade end) as T3
FROM t
order by student
结果
t_ID student T1 T2 T3
----------------------------------
1 St1 A NULL NULL
4 St1 NULL B NULL
7 St1 NULL NULL A
2 St2 B NULL NULL
5 St2 NULL B NULL
8 St2 NULL NULL C
3 St3 B NULL NULL
6 St3 NULL A NULL
9 St3 NULL NULL B
但是,我们发现有必要按“学生”字段对结果进行分组。当我们分组时,我们必须指定一个聚合函数来指定在具有相同值“student”的多个行的情况下要保留的值。在这种情况下,我们使用“max”函数来丢弃null。
SELECT
t_ID,
student,
max(case when t.test = 'T1' then t.grade end) as T1,
max(case when t.test = 'T2' then t.grade end) as T2,
max(case when t.test = 'T3' then t.grade end) as T3
FROM t
GROUP BY student
ORDER BY student
结果
t_ID student T1 T2 T3
-----------------------------
7 St1 A B A
8 St2 B B C
9 St3 B A B
最后的说明。由于我们还没有按t_ID分组,也没有为它指定聚合函数,因此您应该假设每行的t_ID值是每个组的随机值。小心一点。