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
我尝试了不同的事情,但我陷入了如何生成这样的问题打印输出。任何帮助表示赞赏!
I am new to SQL. I have a database with data for different exams, for example:
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
Then, I would like to print a report using the Tests (T1, T2 and T3) as columns:
Student T1 T2 T3
----------------------
St1 A B A
St2 B B C
St3 B A B
I have tried different things, but I got stuck on how to produce such a printout. Any help is appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
使用:
Use:
不久前我问了一个类似的问题。您需要类似于数据透视表的东西,但是,这在 SQLite 中不可用(据我所知)。
I asked a similar question a while back. You need something akin to a pivot table, but, that's not available in SQLite (as far as I know).
有几种方法可以做到这一点,这两种方法(在纯 SQL 中而不是生成 SQL 命令的代码中)都需要已知并固定列数。最直接的实现是:
这几乎可以在包括 SQLite 在内的任何环境中工作,并且可以使用标量值函数 GetTest() 使其变得更加优雅,该函数将获取学生和测试编号并返回成绩。然而,无论如何,这既不是高效的,也不是无法改变的。它将在表中查询 N 次 N 次测试,如果您添加第 4 个测试,则必须更改此查询以将其包含在报告中。
如果 Student 和 Test 的组合是唯一的,并且您正在使用具有 Pivot 功能的数据库(显然 SQLite 没有),则可以将 Pivot 查询与任何聚合器(MAX/MIN/AVG/具有单个值的集合的总和就是该值)。 MSS2005 中的以下工作:
这将具有更高的性能,并且更加优雅。 AFAIK 仍然无法动态确定列列表,但如果您从应用程序代码进行此查询,或者使用 MS SQL Server 中的 sp_executesql 内置存储过程从另一个存储过程生成查询,则生成它们很简单功能。
There are a couple of ways to do it, both of which (in pure SQL and not code generating a SQL command) require the number of columns to be known and fixed. The most straightforward to implement would be:
This will work in practically any environment including SQLite, and it could be made a bit more elegant with a scalar-valued function GetTest() that would take the student and test number and return the grade. However, in any case, this is neither performant nor closed to change; it will query the table N-squared times for N tests, and if you add a 4th test, this query will have to change to include it in the report.
If the combination of Student and Test is unique, and you're working in a database with Pivot functionality (which apparently SQLite doesn't have), you can use a Pivot query with just about any aggregator (the MAX/MIN/AVG/SUM of a set with a single value is that value). The following works in MSS2005:
This will be more performant, and it's far more elegant. The column lists still cannot be dynamically determined AFAIK, but they're trivial to generate if you're making this query from application code, or using the sp_executesql built-in stored proc in MS SQL Server to generate a query from another stored proc or function.
我相信,如果您要扩展此系统以包含更多信息,那么您可以从重新设计数据库中受益,我会像这样构建它:
表名称 = 粗体
列名称 = 斜体
学生:
测试的其他信息:
测试成绩
这种结构基于一种称为数据库规范化的思想(如果你用谷歌搜索,你会得到很多信息)。我将在下面给您一个部分总结,但是如果您要执行大量 SQL,您应该自己阅读:
首先要知道的是,主键只是一个唯一标识符,它通常不是 SQL 的一部分。信息(但是,由于它是唯一的,每个数据的主键必须具有不同的值),并且外键是一种使用被引用者的主键从一个表中的行引用另一个表中的行的方法:例如这里,每个年级的外键 SID 根据主键 SID 引用单个学生。
例如,学生 1 的 SID 为 1,并且他的所有测试的 SID 列中均为 1。学生 2、3、4 等也同样。
规范化的基本思想是,所有唯一数据仅存储一次,然后在使用它的其他地方引用(如果您看一下示例中键的结构,所有学生信息都存储在一个表中,并且然后在他们的测试成绩中引用,而不是在每个成绩中重复)。
要从这些表中检索您想要的内容,我将使用它(用 PHP 编写):
您可以在 echo 语句中为其添加格式,还可以打印您选择添加的任何额外信息。如果您有任何疑问,请询问他们。
编辑:我已经阅读了其他人,并同意他们的方法很可能是优越的,我唯一不确定的是数据透视表是否可以扩展以处理不同数量的测试,如果它可以(或者你不需要),那么我建议他们的方法,否则我觉得这可能在你的应用程序中占有一席之地。
I believe that if you are going to expand this system to include more information then, you could benefit from reworking your database, I would build it like so:
Table name = Bold
Column name = Italicized
Students:
Tests:
Test Grades
This structure is based on an idea called database normalizing (you'll get lots of information if you google it). I will give you a partial summary below, but if you're going to do lots of SQL you should read up on it yourself:
The first thing to know is that a primary key is just a unique identifier, it is not usually part of the information (however, since it is unique every datum must have different value for its primary key), and a foreign key is a way to reference a row in one table from a row in another table, using the referencee's primary key: for example here the foreign key SID in each grade references a single student, based on their primary key SID.
e.g. student one has SID 1 and all his tests have 1 in the SID column. same for student 2, 3, 4, and so on.
The basic idea of normalizing, is that all unique data is stored only once and then referenced in the other places that use it (If you take a look at how the keys are structured in the example, all student information is stored in a table and then referenced in their test grades, instead of being duplicated in each grade).
To retrieve what you want from these tables I would use this (its written in PHP):
You can add formatting to this in the echo statements and also print any of the extra information you choose to add. If you ave any questions please ask them.
EDIT: I have read the others, and agree that their method is in all likelihood superior, the only thing I'm not sure about is whether pivot tables can expand to handle a varying number of tests, if it can (or you won't need to), then I suggest their method, otherwise I feel this might have a place in your application.
我想为 @OMG_Ponies 答案添加一些解释,因为它对于 SQL 无超级用户(比如我自己)可能很有用
让我们创建一个示例表并添加虚拟数据:
所以我们有以下内容:
使用语句
case when ... then ... end
可以获得所需的列结果
但是,我们看到有必要按字段“student”对结果进行分组。当我们分组时,我们必须指定一个聚合函数来指定在有多于一行具有相同“student”值的情况下要保留哪个值。在这种情况下,我们使用“max”函数来丢弃空值。
结果
最后说明。由于我们还没有按 t_ID 进行分组,也没有为其指定聚合函数,因此您应该假设每一行的 t_ID 值是每组的随机值。对此要小心。
I would like to add some explanation to @OMG_Ponies answer because it could be useful for SQL no-super-users (like myself)
Let's create an example table and add the dummy data:
So we have the following:
Using the statement
case when ... then ... end
it is possible to get the desired columnsResult
However, we see that it is necessary to group the results by the field "student". When we group we have to specify an aggregate function to specify which value to keep in case of having more than one row with the same value of "student". In this case we use the "max" function, to discard the null's.
Result
Final note. Since we have not grouped also by t_ID, nor we have specified an aggregate function for it, you should assume that the value of t_ID of each row is a random one of each group. Be careful with that.
试试这个
使用您的表名称而不是“tablename”。
Try This
Use your table name instead of "tablename".