【问题标题】:Challenging MySQL query for html/PHP report对 html/PHP 报告具有挑战性的 MySQL 查询
【发布时间】:2012-11-07 19:08:23
【问题描述】:

对于优秀的 MySQL 编码器来说,这是一个挑战。 我们将非常感谢有关查询的帮助,以创建在 html/PHP 页面中显示的 MySQL 报告。

我们知道如何收集和存储数据,并拥有 PHP 报表布局,但不知道如何构造查询。

我们有两个 MySQL 表——“visitors”和“buyers”。

  1. Visitors 表 – 用于通过访问我们网站的访问者 标识 sales_rep 和众多之一的特定 URL 他们自己创建的营销代码。
  2. Buyers 表 – 为那些买东西的人准备的。

访问者可以通过以下链接访问我们的网站,例如:

www.sales_rep.website.com/index.php?marketing=code1/code2/code3

在“访问者”表中,我们包含三个字段:

  • sales_rep
  • 日期
  • marketing_CODE –(在这种情况下是字符串中的“code1/code2/code3”,但每个 sales_rep 可以根据他们的广告活动有多个 marketing_CODES;例如“code1a/codeTX/codeM2”和“market- z/ad-123")

当访问者购买商品时,我们会将其添加到“买家”表中,其中包括:

  • sales_rep
  • 日期
  • marketing_TYPE –(可以是“URL”、“referral”或其他类型)
  • marketing_VALUE –(如果 marketing_TYPE 是 URL,则为 marketing_CODE)

我们需要查看每个特定销售代表的报告,在任何指定月份,按营销代码排序,仅针对 marketing_TYPE == "URL"。

此报告需要显示每个 marketing_CODE 的访客和买家活动的每周细分,如下所示:

为清楚起见,在上表中,在第 1 周,8 位访问者通过带有“code1/code2/”的链接进入网站,其中 5 人购买了东西。

我们尝试从以下内容开始查询,但不知道从哪里开始:

  1. $chosen_month = $_POST['chosen_month'];
  2. SELECT * FROM visitors INNER JOIN buyers ON sales_rep WHERE marketing_type = "URL" AND sales_rep = '$sales_rep' AND date('Y-m') = $'chosen_month' ;
  3. 使用while 语句,我们将为找到的每条记录生成表格单元格。使用它,我们知道如何列出每条记录,但我们无法弄清楚如何显示一次非不同记录,显示它们的计数,然后显示不同的记录。

感谢您的时间和帮助。

【问题讨论】:

  • 无论您在这里做什么,都会受益于一些proper SQL escaping。将$_POST 值直接注入您的查询是一个非常糟糕的想法
  • 感谢您的信息。我刚刚开始学习如何防止 sql 注入。在 PHP 中实际创建变量时,我们将使用 mysql_real_escape_string 函数来保护数据。该帖子来自一个下拉菜单,所以这应该足以保护它,对吧?
  • 您必须在任何和所有值上使用mysql_real_escape_string。确保您拥有每一个可能是一个挑战,这就是为什么使用PDO 而不是已弃用的mysql_query 接口。请务必使用 SQL injection testing tool 测试您的应用,以确保您没有完全暴露。
  • 再次感谢。我一定会阅读 PDO。我们的大部分代码都是使用mysql_query 编写的。它和 PDO 的语法有何不同?

标签: php html mysql


【解决方案1】:

这是我对您查询的建议。

首先,我需要根据日期字段找出周数,所以我使用了this question中的答案:

SELECT  WEEK(dateField, 5) -
        WEEK(DATE_SUB(dateField, INTERVAL DAYOFMONTH(dateField) - 1 DAY), 5) + 1

从现在开始,我将上面的结果称为@week,以使事情更具可读性:)

然后,我只从其中一张表开始,试图查看销售代表每个月有多少访问者:

select rep, 
  , SUM(CASE @week WHEN 1 THEN 1 ELSE 0 END) as Week1
  , SUM(CASE @week WHEN 2 THEN 1 ELSE 0 END) as Week2
  , SUM(CASE @week WHEN 3 THEN 1 ELSE 0 END) as Week3
  , SUM(CASE @week WHEN 4 THEN 1 ELSE 0 END) as Week4
  , COUNT(*) as Total
from visitors
group by rep

现在我们得到了这个信息,我们将把它用于买家,然后加入这两个子查询的结果,如下所示:

select v.rep
, v.Week1 , b.Week1
, v.Week2 , b.Week2
, v.Week3 , b.Week3
, v.Week4 , b.Week4
, v.Total, b.Total
from (
     select rep, 
        , SUM(CASE @week WHEN 1 THEN 1 ELSE 0 END) as Week1
        , SUM(CASE @week WHEN 2 THEN 1 ELSE 0 END) as Week2
        , SUM(CASE @week WHEN 3 THEN 1 ELSE 0 END) as Week3
        , SUM(CASE @week WHEN 4 THEN 1 ELSE 0 END) as Week4
        , COUNT(*) as Total
     from visitors
     group by rep) as v
     left join (select rep, 
                 , SUM(CASE @week WHEN 1 THEN 1 ELSE 0 END) as Week1
                 , SUM(CASE @week WHEN 2 THEN 1 ELSE 0 END) as Week2
                 , SUM(CASE @week WHEN 3 THEN 1 ELSE 0 END) as Week3
                 , SUM(CASE @week WHEN 4 THEN 1 ELSE 0 END) as Week4
                 , COUNT(*) as Total
                from visitors
                group by rep) as b on v.rep = b.rep

这应该是你要找的!

下面是根据您的情况更新的与上面相同的代码:

select v.rep
    , v.Week1 , b.Week1
    , v.Week2 , b.Week2
    , v.Week3 , b.Week3
    , v.Week4 , b.Week4
    , v.Total, b.Total
from (
        select rep
          , SUM(CASE WEEK(the_date, 5) -
            WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 1 THEN 1 ELSE 0 END) as Week1
      , SUM(CASE WEEK(the_date, 5) -
            WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 2 THEN 1 ELSE 0 END) as Week2
      , SUM(CASE WEEK(the_date, 5) -
        WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 3 THEN 1 ELSE 0 END) as Week3
      , SUM(CASE WEEK(the_date, 5) -
        WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 4 THEN 1 ELSE 0 END) as Week4
      , COUNT(*) as Total
        from visitors
        where sales_rep = '$sales_rep' AND date('Y-m') = $'chosen_month'
        group by rep ) as v
  left join (
        select rep
          , SUM(CASE WEEK(the_date, 5) -
            WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 1 THEN 1 ELSE 0 END) as Week1
      , SUM(CASE WEEK(the_date, 5) -
            WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 2 THEN 1 ELSE 0 END) as Week2
      , SUM(CASE WEEK(the_date, 5) -
        WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 3 THEN 1 ELSE 0 END) as Week3
      , SUM(CASE WEEK(the_date, 5) -
        WEEK(DATE_SUB(the_date, INTERVAL DAYOFMONTH(the_date) - 1 DAY), 5) + 1
            WHEN 4 THEN 1 ELSE 0 END) as Week4
      , COUNT(*) as Total
        from buyers
        where marketing_type = "URL" AND sales_rep = '$sales_rep' AND date('Y-m') = $'chosen_month'
        group by rep) as b on v.rep = b.rep

【讨论】:

  • 感谢您的回复。该代码似乎正在运行,但我无法显示任何数据。我正在使用 while 循环从查询中提取变量,并且我没有收到来自 PHP 或 MySQL 的任何错误。我应该使用不同的方法来提取数据吗?
  • 首先,您应该尝试直接在 sql 中运行查询 - 为此使用 Phpmyadmin 或 Mysql Workbench。一旦您确定结果符合预期,那么您应该尝试在代码中使用该查询。
  • 另外,我看到我为日期列使用了不同的名称:“the_date”而不是您在示例中使用的“日期”。而且您使用的条件 "date('Y-m') = $'chosen_month'" 永远不会起作用,因为它不会按 date 列过滤 - 这里 date 是一个函数。
  • 非常感谢!在比较之前,我将日期更改为 Date_Format 函数。稍作清理后,一切正常。
猜你喜欢
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
相关资源
最近更新 更多