php - 根据用户订阅计算月和日的记录

标签 php mysql

我想计算特定月份和日期的订阅者数量,并以表格格式打印。我有 3 个表(registration、registration_session 和 commodity),我想根据更新日期限制为 30 天的商品表中的注册来统计月和日的记录数。我已经给出了解决方案,它工作正常,但打印最终结果需要很多时间。

编辑: 我的计划是打印全年必须发送的 SMS/语音调用详细信息的总数。但不要计算超过 30 天的记录。请检查下面给出的我的 php 代码,您可能会理解我正在尝试做什么。它正在工作,但问题是,它非常慢。完成任务需要将近一个小时。

最终结果:

          Sunday Monday Tuesday Wednesday Thursday Friday Saturday
January    17333  15455   15368     16348    14827  15054    14637
February   17332  15481   15400     16351    14824  15059    14613
March      17125  15689   15721     16393    14807  14938    14479
April      18542  17426   17485     17941    16414  16427    15972
May        15824  14870   15044     15441    14311  14485    13861
June       15186  14138   14360     14769    13643  13798    13195
July       13496  12602   12837     13163    12168  12228    11669
August     13305  12333   12570     12891    11913  11974    11422
September  13286  12371   12649     12913    11898  11927    11553
October    12893  11773   11912     12390    11407  11516    11097
November   13563  12415   12516     13042    12028  12173    11764
December   13849  12172   12274     13041    11797  12119    11613

我的问题是,如何让它更快?

我的表格: 注册

id  mobile      name        day             state   language    status
1   1234566532  ishtiyaq    'SUN:MON'       up      en          1
2   2313443454  sandeep     'MON:TUE'       up      en          1
3   7436343422  shiv        'MON:TUE:WED'   up      en          1

registration_session

id  reg_id  session         com             distt               status
1   1       'JAN:FEB'       com1:com2:com3  dist1:dist2:dist3   1
2   1       'DEC:JAN:FEB'   com1:com2       dist1:dist2         1
3   2       'APR:MAY:JUN'   com4:com6       dist4:dist8         1

商品

id  state   distt   com     price   date_updated
1   up      distt1  com1    200     2015-04-23
2   up      distt2  com2    420     2015-12-17
3   up      distt4  com3    340     2015-10-16
4   up      distt1  com2    560     2015-09-13
5   up      distt4  com4    320     2015-11-01
6   mp      distt5  com2    322     2015-10-01
7   dl      distt7  com5    120     2015-12-11

结果:

|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
|        |  Sunday       |  Monday       |  Tuesday      |  Wednesday    |  Thursday     |  Friday       |  Saturday     |
|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
|January |  9876-14150   |  8533-12026   |  8491-11991   |  9136-13027   |  8196-11581   |  8404-12015   |  8244-11748   |
|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
|Febury  |  9845-13450   |  8521-54026   |  5441-13491   |  1136-13217   |  7196-16531   |  8704-12613   |  2244-14748   |
|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
......

我的解决方案:

$arr_months = array('JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC');
$arr_days = array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT');

foreach ($arr_months as $month) {
    foreach ($arr_days as $day) {
        $total_msg = 0;
        $total_rec = 0;

        $sql1 = "SELECT registration.mobile,
                  registration.id,
                  registration.state,
                  registration.language,
                  registration_session.com,
                  registration_session.distt
             FROM registration_session
                 INNER JOIN registration
                     ON registration_session.reg_id = registration.id
                 WHERE registration_session.session LIKE '%" . $month . "%'
                     AND registration.status = 1
                     AND registration.language = 'en'
                     AND registration.day LIKE '%" . $day . "%'
                 ORDER BY registration.mobile";
        $result1 = mysqli_query($con, $sql1);

        while ($row1 = mysqli_fetch_assoc($result1)) {
            $state = $row1['state'];
            $commodity = explode(':', $row1['commodity']);
            $distt = explode(':', $row1['distt']);
            $count = count($commodity);

            $found = false;
            while ($count > 0) {
                $sql2 = "SELECT * FROM commodity
                            WHERE date_updated BETWEEN CURDATE() - INTERVAL 30 DAY AND SYSDATE()
                            AND state = '".$state."'
                            AND distt = '".$distt[$count - 1]."'
                            AND cv_commodity = '".$commodity[$count - 1]."'";
                $result2 = mysqli_query($con, $sql2);

                if (mysqli_num_rows($result2) > 0) {
                    $total_msg++;
                    $found = true;
                }
                $count--;
            }
            if ($found == true) {
                $total_rec++;
            }
        }
    }
}



--
-- Table structure for table `commodity`
--

CREATE TABLE IF NOT EXISTS `commodity` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `state` varchar(100) NOT NULL,
  `distt` varchar(100) NOT NULL,
  `com` varchar(100) NOT NULL,
  `price` int(10) NOT NULL,
  `date_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

建表语句:

CREATE TABLE IF NOT EXISTS `registration` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `mobile` int(10) DEFAULT NULL,
  `name` varchar(22) NOT NULL,
  `day` varchar(255) NOT NULL,
  `state` varchar(50) NOT NULL,
  `language` varchar(2) NOT NULL,
  `status` int(1) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;


CREATE TABLE IF NOT EXISTS `registration_session` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `reg_id` int(10) DEFAULT NULL,
  `session` varchar(255) NOT NULL,
  `com` varchar(255) NOT NULL,
  `distt` varchar(50) NOT NULL,
  `status` int(1) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `reg_id` (`reg_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `commodity` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `state` varchar(100) NOT NULL,
  `distt` varchar(100) NOT NULL,
  `com` varchar(100) NOT NULL,
  `price` int(10) NOT NULL,
  `date_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

最佳答案

如果我没看错你的循环,这个脚本就会对数据库进行大量调用。第一个查询是 weekdays * months(84 个查询),然后是这 84 个循环中每个循环的状态、商品和 distt 的所有可能组合。

我建议一次获取两个查询的所有结果,然后循环遍历 PHP 中的记录,以按月、日和州、商品和 Distt 形成结果。

如果您不需要那种级别的粒度,我也会汇总您的查询。在第一个示例中:

SELECT 
    registration.day,
    registration.mobile,
    registration.id,
    registration.state,
    registration.language,
    registration_session.com,
    registration_session.session,
    registration_session.distt,
    COUNT(1) AS cnt
FROM 
    registration_session
INNER JOIN 
    registration ON registration_session.reg_id = registration.id
WHERE 
    AND registration.status = 1
    AND registration.language = 'en'
GROUP BY
    registration.day,
    registration.mobile,
    registration.id,
    registration.state,
    registration.language,
    registration_session.com,
    registration_session.session,
    registration_session.distt

商品一:

SELECT 
    state,
    distt,
    cv_commodity,
    COUNT(1) AS cnt
FROM 
    commodity
WHERE 
    date_updated BETWEEN CURDATE() - INTERVAL 30 DAY AND SYSDATE()
GROUP BY
    state,
    distt,
    cv_commodity

然后您的 PHP 循环遍历结果:

$arr_months = array('JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC');
$arr_days = array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT');

foreach ($arr_months as $month) {
    foreach ($arr_days as $day) {
        $total_msg = 0;
        $total_rec = 0;

    foreach ($result1 AS $row1) {
        if (strpos($row1['session'],$month) !== false AND strpos($row1['day'],$day) !== false){
            $state = $row1['state'];
            $commodity = explode(':', $row1['com']);
            $distt = explode(':', $row1['distt']);
            #$count = number of commodities * number of records in db for this row
            $count = count($commodity) * $row1['cnt']; 

            #Check if State/Commodity exist in $result2 using the same strpos method above
            #Store aggregates for each month/day in a new array to display results
        }
    }
}
}

我会采用这种方法来优化性能,方法是减少数据库查询的数量,汇总结果,从而减少需要预先加载到内存中的记录,然后循环获取我的结果。

关于php - 根据用户订阅计算月和日的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34559239/

相关文章:

mysql - DROP SCHEMA 后留下的旧表碎片

javascript - 如何在JS中使用ajax请求的结果?

javascript - 单击按钮将一个功能更改为第二个功能

mysql - SQL 查询返回超出范围内允许数量的记录

MySQL:修剪 *both* 空格和换行符

mysql - SQL 请求 : Display people who are not friend

php - 将表单结果发送到另一个页面 php mysql

php - 插入新行时移动 mysql 行?

php - 我正在尝试在 php 中运行邮件表单。这是带有 Bootstrap 3.0 的 HTML

java - 如何在准备好的语句java中使用特殊字符