MySQL查询问题,我搞不懂

MySQL查询问题,我搞不懂,sql,mysql,pivot,Sql,Mysql,Pivot,我希望有人能帮助我。我有一个记录导入作业的表。我需要一个查询,该查询将生成一个矩阵,其中包含纵轴上的表名、横轴上的导入日期以及在该日期为该表在矩阵单元中导入的记录总数。我不在乎是否必须创建一个临时表,但整个过程都必须在MySQL中完成 下面是我们事件日志表的简化示例。它不仅有更多的场,而且我们进口了更多的表。因此,解决方案应该考虑查询表名。您会注意到,数据每天可以多次导入到表中,如记录5和6所示 id table_name import_date num_recs ---

我希望有人能帮助我。我有一个记录导入作业的表。我需要一个查询,该查询将生成一个矩阵,其中包含纵轴上的表名、横轴上的导入日期以及在该日期为该表在矩阵单元中导入的记录总数。我不在乎是否必须创建一个临时表,但整个过程都必须在MySQL中完成

下面是我们事件日志表的简化示例。它不仅有更多的场,而且我们进口了更多的表。因此,解决方案应该考虑查询表名。您会注意到,数据每天可以多次导入到表中,如记录5和6所示

id  table_name  import_date          num_recs 
----+-----------+--------------------+------- 
0   customer    2010-06-20 00:00:00  10        
1   order       2010-06-20 00:00:00  15        
2   customer    2010-06-21 00:00:00  5         
3   order       2010-06-21 00:00:00  6         
4   customer    2010-06-22 00:00:00  1         
5   order       2010-06-22 00:00:00  6         
6   order       2010-06-22 00:00:00  1         
我们正在寻找这样的结果。不一定要精确

table_name  06-20 06-21 06-22
------------+-----+-----+------
customer    |  10 |   5 |   1
order       |  15 |   6 |   7

表单的输出如何:

table_name   date    imports
------------+-------+--------
customer    | 06-20 |   10
customer    | 06-21 |   5
order       | 06-20 |   15
order       | 06-21 |   6
通过以下方式,您可以通过一个简单的组完成此操作:


否则,您的查询将变得非常糟糕。

MySQL无法执行pivot查询,但您可以在两个查询中执行,使用第一个查询的结果作为下一个查询的SQL:

SELECT 'SELECT table_name'
UNION
SELECT CONCAT(', SUM(IF(import_date = "',import_date,'", num_recs,0)) AS "',DATE_FORMAT(import_date, "%m-%d"),'"')
FROM event_log
GROUP BY import_date
UNION
SELECT 'FROM event_log GROUP BY table_name'
然后执行该查询的输出以获得最终结果,例如,对于您的示例,您将获得:

SELECT table_name                                                           
, SUM(IF(import_date = "2010-06-20", num_recs,0)) AS "06-20"
, SUM(IF(import_date = "2010-06-21", num_recs,0)) AS "06-21"
, SUM(IF(import_date = "2010-06-22", num_recs,0)) AS "06-22"
FROM event_log GROUP BY table_name

您可以编写一个存储过程来连接、准备并执行第一个查询的结果,或者,如果这都是从shell脚本运行的,您可以捕获第一个查询的结果,然后将结果反馈回mysql。

我认为Ben S的做法是正确的。我想在这里尽我所能,以防对任何人都有帮助,谁知道呢

这里有一种方法,可以获取两个任意日期并将它们拆分为时间块,然后对每个块中的其他数据执行一些聚合函数。在您的情况下,该区块可能是一天,开始日期可能是当前日期前30天,结束日期可能是当前日期。每个块都可以返回一些感兴趣的聚合度量。在您的情况下,这可能是“进口”的总和

选择t1.table\u name作为table\u name,t1.imports作为imports FROM选择SUM`imports`AS imports,CEIL UNIX\u TIMESTAMP-UNIX\u TIMESTAMP`import\u date`/作为RANGE FROM``其中`import\u date`介于和GROUP BY RANGE ORDER BY RANGE DESC之间,作为t1

这可能一点帮助都没有,但如果真的有帮助,那就太好了。它很容易修改,可以将每个范围的开始日期作为日期列返回。要明确的是,这与Ben的解决方案提供的功能完全相同,但是如果您的所有日期都不是00:00:00,那么它将起作用,而这将导致他的GROUP BY on the date列失败

要想知道报税表是什么样子的,请看Ben的答案,然后在心里删除日期栏。但是,正如我所说的,可以很容易地将该列添加回这个查询中。FWIW,我已经在超过400万行的表上使用了这个方法,它仍然在<1秒的时间内运行,这对于我来说已经足够好了


Hamy

/me正在等待关于动态日期的消息……你要接受其中一个答案吗?请在一条语句中查看我的查询,了解如何执行。这不是动态SQL,只是必要的查询。我没有说这是动态SQL。只是一个动态解决方案:-因为第一个查询返回多行,所以不能直接使用mysql的prepared语句,但可以编写一个存储过程来连接、准备并执行第一个查询的输出。或者,您可以从shell脚本捕获第一个查询的输出,然后将其反馈到mysql中。但是,是的,实际上动态SQL必须在存储过程中。+1:为了让你不受哈米有根本缺陷的维基答案的影响。很有可能做一些聪明的事情,将行转换为列。我将避免对答案进行批评。目前为止,我试图尝试这样做,但这是解决问题的错误方法。听本的回答。如果您的工作依赖于您在原始布局中提供它,而您的老板对关系数据库一无所知,那么从MSExcel或OpenOffice运行查询并生成透视表。然后开始寻找另一份工作,因为很快他会要求你组织第一次载人火星任务,使用很多橡皮筋。其他数据库,如PostgreSQL、MS-SQL,都有内置功能,可以做透视表/交叉表/任何你想叫它们的东西。要求用户做pivot表或任何需要他们付出更多努力的事情有时不是这样做的,我们作为开发人员应该能够克服mysql的局限性。使用SQL生成SQL是一个标准的工具,不是很多橡皮筋。@symcbean:关于标准pivot查询有什么可批评的?只有SQL Server 2005+和Oracle 11g+具有PIVOT/UNPIVOT语法。我不认为在Excel/Access中使用此查询作为更改的第一阶段比完全在SQL查询中使用要好…@Hamy:数据的哪一部分
在列中而不是行中按日期进行nning,您不明白吗?这个答案提供了您需要的数据。如果您需要以另一种形式显示它,只需在演示代码中这样做即可。将行转换为列并不是什么大问题。或者还有其他东西绝对要求mysql的结果集采用特定的形式吗?像runrig和我这样的答案的要点是,你不必在SQL之外做这些工作,从思想上删除日期列。你不认为我不知道你否决了我吗?你能不能更幼稚一点呢?正如你们中的一些人提到的,解决方案是多个查询和一些PHP处理。
SELECT table_name                                                           
, SUM(IF(import_date = "2010-06-20", num_recs,0)) AS "06-20"
, SUM(IF(import_date = "2010-06-21", num_recs,0)) AS "06-21"
, SUM(IF(import_date = "2010-06-22", num_recs,0)) AS "06-22"
FROM event_log GROUP BY table_name