在Chartjs

时间:2018-01-25 01:16:32

标签: php mysql sql database charts

我的用户表中包含免费用户或付费用户的标志以及注册日期。像

这样的东西
+------------+-----------+--------------+
| USERNAME   | FREE_USER | DATE_OF_REG  |
+------------+-----------+--------------+
| user_name1 | y         | 2018-01-14   |
| user_name2 | n         | 2017-12-23   |
| user_name3 | y         | 2017-12-12   |
| user_name4 | y         | 2017-11-19   |
| user_name5 | n         | 2017-09-13   |
| user_name6 | y         | 2017-08-27   |
| user_name7 | n         | 2017-07-06   |
+------------+-----------+--------------+

我需要过去6个月内free_users和paid_users的数量,如果一个月内没有用户注册,则应该将0作为免费和付费计数。

我想为免费用户和付费用户创建折线图,就像在此示例中一样(http://www.chartjs.org/samples/latest/charts/line/basic.html)。为此我需要以逗号(,)分隔格式的数据,如:

month_of_registration:[' August',' September',' October',' November',' December' ,' 1月']

free_users_count_for_related_month:[0,1,0,1,0,1,1]

paid_users_count_for_related_month:[1,0,1,0,0,1,0]

如何在PHP中使用mysql查询实现此目的。

我写了这个查询:

SELECT MONTH(date_of_reg) as monthno, MONTHNAME(date_of_reg) as month_name, YEAR(date_of_reg) as year,
COUNT(CASE WHEN `free_user` = 'y' THEN 1 END) AS free_user,
COUNT(CASE WHEN `free_user` = 'n' THEN 1 END) AS paid, 
COUNT(CASE WHEN `free_user` != '' THEN 1 END) as total_users
FROM tbl_agents GROUP BY MONTH( date_of_reg ) ORDER BY year, monthno

但我没有达到我想要的目标。

2 个答案:

答案 0 :(得分:3)

您需要为这几个月生成6行,因为注册中可能存在空白,并且您需要决定何时开始,我使用下面的当前日期作为该点,但它可以是任何想要的日期。注意我从那个日期开始倒退。

此子查询将日期与当月的开头和下个月的第一天进行比较:

set @datum := DATE_FORMAT(current_date, '%Y-%m-01');
...
cross join (select @datum dt_fm, @datum + interval 1 month dt_to) d

然后,当加入6行数字(0到5)时,我们计算过去6个月的日期范围,然后它们允许我们将注册放入每月的桶中进行计数。

set @datum := DATE_FORMAT(current_date, '%Y-%m-01');

select
       monthname(dt_fm - interval n.n month) mnth
     , dt_fm - interval n.n month dt_fm
     , dt_to - interval n.n month dt_to
     , count(case when t.free_user = 'y' then 1 end) free_users
     , count(case when t.free_user = 'n' then 1 end) paid_users
from (
    select 0 n union all
    select 1 n union all
    select 2 n union all
    select 3 n union all
    select 4 n union all
    select 5 n
    ) n
cross join (select @datum dt_fm, @datum + interval 1 month dt_to) d
left join tbl_agents t on t.DATE_OF_REG >= dt_fm - interval n.n month
                      and t.DATE_OF_REG <  dt_to - interval n.n month
group by
       monthname(dt_fm - interval n.n month)
     , dt_fm - interval n.n month
     , dt_to - interval n.n month
order by dt_fm
;

结果:

|      mnth |      dt_fm |      dt_to | free_users | paid_users |
|-----------|------------|------------|------------|------------|
|    August | 2017-08-01 | 2017-09-01 |          1 |          0 |
| September | 2017-09-01 | 2017-10-01 |          0 |          1 |
|   October | 2017-10-01 | 2017-11-01 |          0 |          0 |
|  November | 2017-11-01 | 2017-12-01 |          1 |          0 |
|  December | 2017-12-01 | 2018-01-01 |          1 |          1 |
|   January | 2018-01-01 | 2018-02-01 |          1 |          0 |

请注意,count()函数会忽略null,因此case表达式不使用else,因此当表达式不符合null时,会计算else null没有增加。或者,您可以在案例表达式中使用declare v_timestamp timestamp(6); begin select max("MODIFIED_ON") into v_timestamp from "public"."DAS_ITEM"@PG_LINK; dbms_output.put_line(v_timestamp); end;

我将假设一旦你在数组中得到sql结果,你就可以将其用于图表的输入。

Demo at sqlfiddle

答案 1 :(得分:1)

<强> SQL

首先,你需要创建一个代表过去6个月的表(临时或其他)(tbl_agents可能没有任何记录)。你可以使用&#34; union&#34;语法和date_sub函数(这样可以很容易地跟踪发生的事情):

 select now() as month union 
 select date_sub(now(), INTERVAL 1 MONTH) as month union 
 select date_sub(now(), INTERVAL 2 MONTH) as month union 
 select date_sub(now(), INTERVAL 3 MONTH) as month union 
 select date_sub(now(), INTERVAL 4 MONTH) as month union 
 select date_sub(now(), INTERVAL 5 MONTH) as month union 
 select date_sub(now(), INTERVAL 6 MONTH) as month 

输出:

month 
2018-01-25T03:04:22Z 
2017-12-25T03:04:22Z 
2017-11-25T03:04:22Z
2017-10-25T03:04:22Z 
2017-09-25T03:04:22Z 
2017-08-25T03:04:22Z
2017-07-25T03:04:22Z

然后我们可以在月份使用LEFT JOIN到tbl_agents并使用现有的SQL来实现必要的输出。请注意,我们正在上面的临时表中提供日期:

SELECT MONTH(m.month) AS monthno,
       MONTHNAME(m.month) as month_name,
       YEAR(m.month) as year,
       SUM(CASE WHEN `free_user` = 'y' THEN 1 ELSE 0 END) AS free_user,
       SUM(CASE WHEN `free_user` = 'n' THEN 1 ELSE 0 END) AS paid, 
       SUM(CASE WHEN `free_user` != '' THEN 1 ELSE 0 END) as total_users
FROM (
     select now() as month union 
     select date_sub(now(), INTERVAL 1 MONTH) as month union 
     select date_sub(now(), INTERVAL 2 MONTH) as month union 
     select date_sub(now(), INTERVAL 3 MONTH) as month union 
     select date_sub(now(), INTERVAL 4 MONTH) as month union 
     select date_sub(now(), INTERVAL 5 MONTH) as month union 
     select date_sub(now(), INTERVAL 6 MONTH) as month 
  ) AS m
LEFT JOIN tbl_agents as tb
   ON MONTH(tb.DATE_OF_REG) = MONTH(m.month)
GROUP BY MONTH(tb.DATE_OF_REG)
ORDER BY m.month DESC;

输出:

| monthno | month_name | year | free_user | paid | total_users |
|---------|------------|------|-----------|------|-------------|
|       1 |    January | 2018 |         1 |    0 |           1 |
|      12 |   December | 2017 |         1 |    1 |           2 |
|      11 |   November | 2017 |         1 |    0 |           1 |
|      10 |    October | 2017 |         0 |    0 |           0 |
|       9 |  September | 2017 |         0 |    1 |           1 |
|       8 |     August | 2017 |         1 |    0 |           1 |
|       7 |       July | 2017 |         0 |    1 |           1 |

你可以在这个小提琴中看到这个:http://sqlfiddle.com/#!9/5ad682/12/0

<强> PHP

您的示例中所需的输出是JSON - 因此您需要做的就是从MySQL获取数据并构建表示输出的数组,然后再转换为JSON。例如,它可能看起来像:

<?php

//$data = mysql_query_results

$output_array = array('month_of_registration'              => array(), 
                      'free_users_count_for_related_month' => array(), 
                      'paid_users_count_for_related_month' => array());

foreach( $data as $e ) {
   $output_array['month_of_registration'][] = $e['month_name'];
   $output_array['free_users_count_for_related_month'][] = $e['free_user'];
   $output_array['paid_users_count_for_related_month'][] = $e['paid'];
}

$output_data = json_encode($output_array);