动态选择与第二个表中的字段

时间:2019-01-05 19:21:52

标签: mysql pivot-table

我有3张桌子:

  • 具有学生姓名的表_1(字段= StudentID,FirstName,LastName)

  • 表_2,带有教师姓名(字段= TeacherID,FirstName,LastName,Initials *) (*“初始姓名”字段包含每个教师的姓名缩写:“ JD”代表“ John Doe”,“ FB”代表“ Fred Bloggs”,等等)

  • Table_3以及每个老师给每个学生的成绩(字段= StudentID,TeacherID,成绩)

我想生成一个查询,其中列出所有学生以及他们的成绩;像这样:

/elk

问题在于,FirstName和LastName之后的列应从Table_2的内容中“动态”生成(教师给出成绩)。换句话说,如果将一个新老师添加到该表中(例如Zack Zanny),则(在对所有学生进行评分之后)相同查询应产生如下内容:

server.basePath: "/elk"

我说清楚了吗?

我已经搜索了这个论坛和其他论坛,并尝试阅读mysql数据透视表,但是我必须做错了什么...任何指针将不胜感激。预先感谢。

2 个答案:

答案 0 :(得分:0)

您不能编写一个SQL查询来根据找到的数据值动态扩展其列。选择列表中的列必须在准备查询时固定。

因此,在编写查询之前,您需要知道所有教师ID。一种方法是查询它们:

SELECT TeacherID FROM Table_2;

然后,基于该查询的结果,您的应用程序代码需要构建具有所需列数的数据透视SQL查询。换句话说,使用循环,为上一个查询返回的每个TeacherID的选择列表添加一列。

SELECT st.FirstName, st.LastName,
  MAX(CASE TeacherId WHEN 'JD' THEN Grade END) AS `JD`,
  MAX(CASE TeacherId WHEN 'FB' THEN Grade END) AS `FB`,
  MAX(CASE TeacherId WHEN 'ZZ' THEN Grade END) AS `ZZ`
FROM Table_1 AS st
LEFT OUTER JOIN Table_3 AS gr ON st.StudentId = gr.StudentId
GROUP BY st.FirstName, st.LastName;

MAX()函数只是为了满足聚合查询的规则:select-list中的每一列都必须按GROUP BY子句中的名称进行命名,或者位于MAX()之类的聚合函数中。我假设每个学生每位老师都会有一个年级,所以我也可以使用MIN()甚至AVG()。

要进行数据透视查询,您必须在查询中显式地写入列,但是您可以通过首先发现存在哪个教师ID来自动完成该过程。

另一种选择是编写一个将学生加入成绩的查询,这意味着您的应用程序将为每个学生获取多行-每位老师一行。

SELECT st.FirstName, st.LastName, TeacherId, Grade
FROM Table_1 AS st
LEFT OUTER JOIN Table_3 AS gr ON st.StudentId = gr.StudentId;

然后,您将结果遍历到您的应用中,并根据需要以表格方式显示。

没有办法解决这个问题,要么编写一些应用程序代码以在准备查询之前构建查询,要么使用固定的查询,但是在获取原始数据后编写一些应用程序代码以制表结果数据。

无论哪种方式,代码都不是火箭科学。

答案 1 :(得分:0)

MySQL本身不支持动态数据透视,您必须使用动态sql:

  • 查询教师表以列出所有ID和首字母缩写
  • 使用结果构建SQL查询
  • 运行查询

This SO post给出了一个有效的示例,我为您的用例做了如下修改:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(IF(g.TeacherID = ''',
      TeacherID,
      ''', g.grade, NULL)) AS ',
      Initials
    )
  ) INTO @sql
FROM table_2;

SET @sql = CONCAT('SELECT 
        s.firstname,
        s.lastname,
        ', @sql, ' 
    FROM
        table_3 g
        INNER JOIN table_1 s ON s.studentid = g.studentid
    GROUP BY 
        s.studentid,
        s.firstname,
        s.lastname';

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;