CREATE TABLE activities(activityid, name);
CREATE TABLE activity_scores(activityid, studentid, score);
CREATE TABLE students (id, name);
有没有办法编写一个SELECT查询,以这种格式为每个学生生成一个结果?
studentid | studentname | activity1_score | activity2_score | activity3_score [...]
使用多个查询执行此操作非常简单:
for each studentid in "select id from students":
print studentid
for each activity in "select activityid from activities":
select score from activity_scores where studentid = studentid
print score
(伪代码,我知道这不准确)
当然,有一种方法可以使用单个SELECT查询创建此结果,对吗?
答案 0 :(得分:3)
MySQL,SQLite和其他RDBMS都有一些名为GROUP_CONCAT
的东西
哪个应该做你想要的(没有测试 - 不知道你在activity_scores表上的连接条件):
SELECT students.studentid
, students.studentname
, GROUP_CONCAT(activity_scores.score)
FROM activity_scores
INNER JOIN activities
ON activities.activityid = activity_scores.activityid
INNER JOIN students
ON students.studentid = activities.studentid
GROUP BY students.studentid
, students.studentname
但是smarter folks than me可能会说做这样的事情会混淆两个不同的步骤,这些步骤在分开时最容易处理:
答案 1 :(得分:2)
您基本上在寻找数据透视表。如果您只想使用纯ANSI SQL,则无法执行此操作。 SQL只生成具有可预测列数的结果集(不计算select *')。
但是,可能有一种特定于技术的方法。您使用的是哪个数据库引擎? SQL Server 2005能够执行数据透视表。
答案 2 :(得分:1)
如果活动是已知的并且可以在查询中指定,那么相对容易,如果有点冗长,假设您的SQL方言支持它。例如:
SELECT s.id, s.name,
(SELECT score FROM activity_scores as JOIN activities a ON a.activityid = as.activityid WHERE studentid = s.id AND a.activityname = 'Basketball') basketball_score,
(SELECT score FROM activity_scores as JOIN activities a ON a.activityid = as.activityid WHERE studentid = s.id AND a.activityname = 'Football') football_score,
...
基本上这称为交叉表查询。如果你想动态地做它然后更难,你可能需要求助于代码或存储过程,因此将取决于你的数据库。这是一个example using SQL Server。
答案 3 :(得分:1)
此结果集形状冒犯了关系代数(SQL所基于的)。请参阅SQL反模式帖子#2 What are the most common SQL anti-patterns?
您应该发出此查询并在客户端上格式化结果:
SELECT s.name, a.name, x.score
FROM Activity_Score as x
JOIN Students s
ON x.StudentID = s.StudentID
JOIN Activity a
ON x.ActivityID = a.ActivityID
ORDER BY s.name, a.name, x.score
答案 4 :(得分:1)
其中一个most frequently asked questions on SO。
ANSI SQL不支持这一原因的原因是结果集没有明确定义 - 它将具有任意数量的列。
但是,知道列数,可以生成代码来执行此操作,我总是使用PIVOT
运算符为SQL Server 2005生成代码的示例解决方案(列列表是静态的,这就是为什么这个需要使用动态SQL完成动态SQL,然后执行它。
答案 5 :(得分:0)
在SQL Server 2005/2008中,您可以尝试将每个学生的活动/分数作为xml集返回。不理想,但有效。类似的东西:
SELECT s.name,
(select a.name, x.score FROM FROM Activity_Score as x
JOIN Activity a ON x.ActivityID = a.ActivityID
WHERE x.StudentID = s.StudentID FOR XML AUTO) Activities
FROM Students s
ORDER BY s.name