简体   繁体   English

MySql-通过将行转置为列来生成报告的Sql查询或过程

[英]MySql - Sql query or procedure to generate report by transposing rows into columns

This is the first time - I'm trying to do something like this - so please bear with me. 这是第一次-我正在尝试做这样的事情-所以请多多包涵。 This is on MySql. 这是在MySql上。

I am trying to generate a report to see which students have completed which topics and on which dates. 我正在尝试生成一份报告,以查看哪些学生完成了哪些主题以及在什么日期完成。

This is the current query that I run 这是我运行的当前查询

select u.email,t.topic_name,tu.date_created as 'date completed'
from topic_user tu
join topic t ON tu.topic_id = t.topic_id
join user u ON tu.user_id = u.user_id

which will return results like 这将返回类似的结果

email         |    topic_name      |    date completed
abc@gmail.com |    ABC             |    03/01/2012
abc@gmail.com |    DEF             |    03/02/2012
abc@gmail.com |    ABC             |    03/08/2012
abc@gmail.com |    GHI             |    03/08/2012
def@gmail.com |    ABC             |    03/02/2012
def@gmail.com |    XYZ             |    03/10/2012

The way I want to generate the report is have the topic names as column headers and the date they completed it as values 我要生成报告的方式是将主题名称作为列标题,并将其完成日期作为值

email         |    ABC      |    DEF      |    GHI      |    JKL      |    XYZ     
abc@gmail.com | 03/08/2012  | 03/02/2012  | 03/08/2012  |    null     |    null
def@gmail.com | 03/02/2012  |    null     |    null     |    null     |  03/10/2012

Few things to note are: 要注意的几件事是:

1) All the topic names would come from the topic table - even if they have not been completed by the students - the value should appear as null 1)所有主题名称都将来自主题表-即使尚未由学生完成,该值也应显示为null

2) Incase of student abc@gmail.com - he has studied the topic ABC twice - but the report should get the latest date. 2)如果是学生abc@gmail.com-他已经研究了ABC主题两次-但报告应获得最新日期。

I guess I have to write a stored procedure to accomplish this. 我想我必须编写一个存储过程来完成此任务。 Like maybe first pull all the topic names from the topic table and then create a temp view and populate it. 就像首先从主题表中拉出所有主题名称,然后创建一个临时视图并填充它一样。

I would appreciate any help you can provide. 我会很感激您能提供的任何帮助。 Thanks much 非常感谢

I've not tested this, and my experience with MySQL is limited but I hope the below is what you are after. 我还没有测试过,我在MySQL方面的经验有限,但是我希望下面是您所追求的。 It dynamically creates the SELECT statement using the GROUP_CONCAT function, then executes it (This is the bit I am not certain of the way to do it in MySQL). 它使用GROUP_CONCAT函数动态创建SELECT语句,然后执行它(这是我不确定在MySQL中执行它的方式)。

SET @SQL = (
SELECT  CONCAT('SELECT Email,', GROUP_CONCAT(SelectText), ' FROM Topic_User tu INNER JOIN Users u ON u.User_ID = tu.User_ID GROUP BY Email')
FROM    (   SELECT  CONCAT(' MAX(CASE WHEN Topic_ID = ', Topic_ID, ' THEN tu.Date_Created END) AS `', Topic_Name, '`') AS SelectText
            FROM    Topic
        )  AS d);

PREPARE stmt FROM @SQL;
EXECUTE stmt

Of course if your topics are not changing very regularly you could just use: 当然,如果您的主题变化不是很规律,则可以使用:

SELECT  Email,
        MAX(CASE WHEN Topic_ID = 1 THEN tu.Date_Created END) AS ABC,
        MAX(CASE WHEN Topic_ID = 2 THEN tu.Date_Created END) AS DEF,
        MAX(CASE WHEN Topic_ID = 3 THEN tu.Date_Created END) AS GHI,
        MAX(CASE WHEN Topic_ID = 4 THEN tu.Date_Created END) AS JKL,
        MAX(CASE WHEN Topic_ID = 5 THEN tu.Date_Created END) AS XYZ
FROM    Topic_User tu
        INNER JOIN users u
            ON u.User_ID = tu.User_ID
GROUP BY Email

and alter the query each time a new topic is added (This is the query produced by the process above). 并在每次添加新主题时更改查询(这是上述过程产生的查询)。

You could do this with a dynamically generated crosstab query. 您可以使用动态生成的交叉表查询来执行此操作。 The query you want to end up with is something like this - 您想要结束的查询是这样的-

SELECT
    u.email,
    MAX(IF(t.topic_name = 'ABC', tu.date_created, NULL)) AS 'ABC',
    MAX(IF(t.topic_name = 'DEF', tu.date_created, NULL)) AS 'DEF',
    etc
FROM topic_user tu
INNER JOIN topic t
    ON tu.topic_id = t.topic_id
INNER JOIN user u
    ON tu.user_id = u.user_id
GROUP BY u.user_id;

So, in your server side language of choice you would dynamically build your field list based on first querying for a list of topics. 因此,以您选择的服务器端语言,您将基于首先查询主题列表来动态构建字段列表。

You could slightly reduce the overhead of this query by using the topic_ids instead of the topic_names so that you can drop the join to the topics table - 您可以使用topic_ids代替topic_names来稍微减少此查询的开销,从而可以将联接删除到topics表-

SELECT
    u.email,
    MAX(IF(tu.topic_id = 1, tu.date_created, NULL)) AS 'ABC',
    MAX(IF(tu.topic_id = 2, tu.date_created, NULL)) AS 'DEF',
    etc
FROM topic_user tu
INNER JOIN user u
    ON tu.user_id = u.user_id
GROUP BY u.user_id;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM