2010-08-31 51 views
11

我是SQL新手。我有用于不同的检查数据的数据库,例如: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 

我尝试了不同的东西,但我被卡在如何制作这样的打印输出。任何帮助表示赞赏!

+1

使用“代码”按钮进行格式化可让您使用固定宽度的字体,帮助将这些表格排成一列并更具可读性 – ford 2010-08-31 17:29:08

回答

10

用途:

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 
+0

嗨, 您太棒了!非常感谢!它完美解决了! 干杯! -Mike – 2010-08-31 17:40:11

+1

@Mike Santos:不客气,欢迎来到SO。 – 2010-08-31 17:43:37

1

我问过类似的question而回。你需要类似于数据透视表的东西,但是,这在SQLite中不可用(据我所知)。

+0

感谢您的信息!我看到你的问题。 – 2010-09-02 09:41:59

1

我相信,如果你打算把这个系统扩展到包括更多的信息,那么,你可以从返工你的数据库中受益,我将建立它像这样:

表名 =粗体

列名 =斜体

学生

  • SID(主键)
  • 关于学生的其他信息

测试

  • TID(主键)
  • 有关测试
  • 其他信息

测试成绩

  • GID(主键)
  • TID(外键)
  • SID(外键)

这个结构是基于一个叫做数据库正常化的想法(如果你是谷歌的话,你会得到很多信息)。我将在下面给你一个部分总结,但是如果你打算做很多SQL,你应该自己阅读:

首先要知道的是主键只是一个唯一的标识符,它是通常不是信息的一部分(但是,因为它是唯一的,所以每个数据必须具有不同的主键值),并且外键是从另一个表中的一行中引用一行中的行的方式,使用参考者的主键:例如这里的外键SID在每个年级引用单个学生,根据他们的主键SID

例如学生有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语句格式添加到这一点,并同时打印任你选择的额外信息加上。如果您有任何问题,请询问他们。

编辑:我已阅读其他人,并同意他们的方法在所有可能优于,我唯一不知道的是,数据透视表是否可以扩展以处理不同数量的测试,如果它可以(或者你不需要),那么我建议他们的方法,否则我觉得这可能在你的应用程序中有一席之地。

+0

非常感谢您的详细信息!我真的很感激!谢谢! -Mike – 2010-09-02 09:41:07

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 

使用,而不是 “表名” 你的表名。

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次,如果添加第四次测试,则该查询将不得不更改以将其包括在报告中。

如果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内置存储过程从另一个存储过程生成查询,功能。

+0

非常感谢您的信息! – 2010-09-02 09:41:38