如何从MySQL获取高级统计数据?

时间:2009-09-23 22:56:40

标签: php mysql

您好,

我有一个非常大的MySQL数据库,其表格的结构如下:
在exmaple中,DATE采用unix时间戳格式。所以它需要 转换为正常的美国日期格式,这只是我的数据库中的一些记录
ID日期 REG_TYPE
--------------------------------------
1 1251917888 0
2 1251917888 1
3 1251917888 1
4 1251917888 0
5 1251917888 2
6 1251917888 3
7 1251917888 2
8 1251917888 4
9 1251917888 0
10 1251917888 0

问题是我想得到按日期排序的每个REG_TYPE的计数。 下面显示了我想要得到的内容:

日期REGTYPE(0) REGTYPE(1)REGTYPE(2)REGTYPE(3) REGTYPE(4)
-------------------------------------------------- ------------------------------------------------ <无线电通信/> XXXX 4 2 2 1 1
XXXX X X X X X


我想为数据库中的每个日期得到这个,就像摘要一样 每个日期。


任何人都可以建议一个可能的解决方案吗?我必须转换此输出 从MYSQL获取数据后,在PHP中的数组。不使用循环的原因 在PHP中,这是因为数据库太大而且会导致超时
最诚挚的问候

4 个答案:

答案 0 :(得分:5)

您要做的是一个数据透视操作,SQL语法不直接支持它。但是,它并不太复杂,概念上涉及两个步骤:

  1. 将数据“爆破”到多个列中,原始数据集中每行一行。这通常使用CASE WHEN ... ELSE ... END或偶尔使用函数(如oracle中的decode())来完成。我将在下面的示例中使用CASE WHEN,因为它对大多数RDBMS都同样适用
  2. 使用GROUP BY和聚合函数(SUM,MIN,MAX等)将多行折叠到您想要的输出行集中。
  3. 我正在使用此数据集作为示例:

    mysql> select * from foo;
    +----+------------+----------+
    | id | thedate    | reg_type |
    +----+------------+----------+
    |  1 | 1251917888 |        0 | 
    |  2 | 1251917888 |        1 | 
    |  3 | 1251917888 |        1 | 
    |  4 | 1251917888 |        0 | 
    |  5 | 1251917888 |        2 | 
    |  6 | 1251917888 |        3 | 
    |  7 | 1251917888 |        2 | 
    |  8 | 1251917888 |        4 | 
    |  9 | 1251917888 |        0 | 
    | 10 | 1251917888 |        0 | 
    | 11 | 1251831488 |        1 | 
    | 12 | 1251831488 |        2 | 
    | 13 | 1251831488 |        2 | 
    | 14 | 1251831488 |        1 | 
    | 15 | 1251831488 |        3 | 
    | 16 | 1251831488 |        4 | 
    | 17 | 1251831488 |        3 | 
    | 18 | 1251831488 |        5 | 
    | 19 | 1251831488 |        1 | 
    | 20 | 1251831488 |        1 | 
    +----+------------+----------+
    

    第1步是“炸毁”数据集:

    select id
         , thedate
         , case when reg_type = 0 then 1 else 0 end as reg_type_0
         , case when reg_type = 1 then 1 else 0 end as reg_type_1
         , case when reg_type = 2 then 1 else 0 end as reg_type_2
         , case when reg_type = 3 then 1 else 0 end as reg_type_3
         , case when reg_type = 4 then 1 else 0 end as reg_type_4
         , case when reg_type = 5 then 1 else 0 end as reg_type_5
      from foo;
    

    给出:

    +----+------------+------------+------------+------------+------------+------------+------------+
    | id | thedate    | reg_type_0 | reg_type_1 | reg_type_2 | reg_type_3 | reg_type_4 | reg_type_5 |
    +----+------------+------------+------------+------------+------------+------------+------------+
    |  1 | 1251917888 |          1 |          0 |          0 |          0 |          0 |          0 | 
    |  2 | 1251917888 |          0 |          1 |          0 |          0 |          0 |          0 | 
    |  3 | 1251917888 |          0 |          1 |          0 |          0 |          0 |          0 | 
    |  4 | 1251917888 |          1 |          0 |          0 |          0 |          0 |          0 | 
    |  5 | 1251917888 |          0 |          0 |          1 |          0 |          0 |          0 | 
    |  6 | 1251917888 |          0 |          0 |          0 |          1 |          0 |          0 | 
    |  7 | 1251917888 |          0 |          0 |          1 |          0 |          0 |          0 | 
    |  8 | 1251917888 |          0 |          0 |          0 |          0 |          1 |          0 | 
    |  9 | 1251917888 |          1 |          0 |          0 |          0 |          0 |          0 | 
    | 10 | 1251917888 |          1 |          0 |          0 |          0 |          0 |          0 | 
    | 11 | 1251831488 |          0 |          1 |          0 |          0 |          0 |          0 | 
    | 12 | 1251831488 |          0 |          0 |          1 |          0 |          0 |          0 | 
    | 13 | 1251831488 |          0 |          0 |          1 |          0 |          0 |          0 | 
    | 14 | 1251831488 |          0 |          1 |          0 |          0 |          0 |          0 | 
    | 15 | 1251831488 |          0 |          0 |          0 |          1 |          0 |          0 | 
    | 16 | 1251831488 |          0 |          0 |          0 |          0 |          1 |          0 | 
    | 17 | 1251831488 |          0 |          0 |          0 |          1 |          0 |          0 | 
    | 18 | 1251831488 |          0 |          0 |          0 |          0 |          0 |          1 | 
    | 19 | 1251831488 |          0 |          1 |          0 |          0 |          0 |          0 | 
    | 20 | 1251831488 |          0 |          1 |          0 |          0 |          0 |          0 | 
    +----+------------+------------+------------+------------+------------+------------+------------+
    

    接下来,我们在每个日期的输出中折叠为一行,并将每个reg_type_ *列相加,使用或初始查询作为内联视图(也称为“子查询”):

    select thedate
         , sum(i.reg_type_0) as reg_type_0
         , sum(i.reg_type_1) as reg_type_1
         , sum(i.reg_type_2) as reg_type_2
         , sum(i.reg_type_3) as reg_type_3
         , sum(i.reg_type_4) as reg_type_4
         , sum(i.reg_type_5) as reg_type_5
      from (
             select id
                  , thedate
                  , case when reg_type = 0 then 1 else 0 end as reg_type_0
                  , case when reg_type = 1 then 1 else 0 end as reg_type_1
                  , case when reg_type = 2 then 1 else 0 end as reg_type_2
                  , case when reg_type = 3 then 1 else 0 end as reg_type_3
                  , case when reg_type = 4 then 1 else 0 end as reg_type_4
                  , case when reg_type = 5 then 1 else 0 end as reg_type_5
               from foo
           ) i
     group by thedate
     order by thedate asc;
    

    (另请注意,您可以将这两个查询合并为一个,但为了清楚起见,我在这里单独显示它们;至少在MySQL中,这似乎导致更简单的执行计划,这通常意味着更快的执行 - 如总是,在真实的数据集上测试你的SQL性能,不要相信我的话!)

    这给了我们:

    +------------+------------+------------+------------+------------+------------+------------+
    | thedate    | reg_type_0 | reg_type_1 | reg_type_2 | reg_type_3 | reg_type_4 | reg_type_5 |
    +------------+------------+------------+------------+------------+------------+------------+
    | 1251831488 |          0 |          4 |          2 |          2 |          1 |          1 | 
    | 1251917888 |          4 |          2 |          2 |          1 |          1 |          0 | 
    +------------+------------+------------+------------+------------+------------+------------+
    

    这是期望的结果。您可以使用MySQL函数FROM_UNIXTIME将日期转换为DATE,并且在第2部分查询中执行此操作可能是最有效的(评估函数的次数较少,并且对整数组进行比较,而不是DATE - 不确定这在MySQL中是否真的有任何不同。)

答案 1 :(得分:1)

除了你输出的输出(你发布的示例输出是一个数据透视表)之外,你必须使用COUNT BY语句

例如:

SELECT `DATE`, COUNT(*)
FROM `TABLE_NAME`

GROUP BY `REG_TYPE`

答案 2 :(得分:1)

您可以使用以下内容在mysql中模拟数据透视表:

SELECT
 SUM(REG_TYPE = 0) AS reg_type_0,
 SUM(REG_TYPE = 1) AS reg_type_1,
 SUM(REG_TYPE = 2) AS reg_type_2,
 SUM(REG_TYPE = 3) AS reg_type_3,
 SUM(REG_TYPE = 4) AS reg_type_4,
 TO_DAYS(FROM_UNIXTIME(date)) AS day_number
FROM my_table
GROUP BY TO_DAYS(FROM_UNIXTIME(date))

日期操作位可能需要一些调整。

答案 3 :(得分:0)

你可以查询REG_TYPE的所有值(如果你事先不知道它们)然后组装这样的东西(抱歉,我的MySQL生锈了):

select date, 
  SUM(IF(REGTYPE=0, 0, 1) AS REGTYPE0,
  SUM(IF(REGTYPE=1, 0, 1) AS REGTYPE1,
  SUM(IF(REGTYPE=2, 0, 1) AS REGTYPE2,
  SUM(IF(REGTYPE=3, 0, 1) AS REGTYPE3,
  SUM(IF(REGTYPE=4, 0, 1) AS REGTYPE4
  FROM table
  GROUP BY date