【问题标题】:Adding Column to MySQL table query将列添加到 MySQL 表查询
【发布时间】:2017-06-17 14:03:51
【问题描述】:

我有一个相对复杂的查询,其中包含一些我用来为我的销售代表创建“排行榜”的子查询。问题是主要数据是通过 Sale_Date 过滤的,而我需要通过 Install_Date 过滤其中一列(只有 Installs 列)。我正在使用 MySQL 工作台和第 3 方商业智能平台以一种可展示的方式输出数据。下面是我目前正在做的事情的简化版本,但它显然不起作用或没有给我想要的东西。

select `Rep`, `Sales`, `Passed Credit`, `Sales Scheduled`, Installs
from 
    (select Rep_Name as `Rep`, count(*) as `Sales`..., count(...) as `Sales Scheduled`
        from ss.customers
            left join ss.users
                on customers.rep_id = users.id
        where Sale_Date between curdate() - interval 6 day and curdate()
        group by Rep_Name with rollup) cust,
    (select Rep_Name, count(*) as `Installs`
        from ss.customers
            left join ss.installs
                on customers.id = installs.id
            left join ss.users
                on customers.rep_id = users.id
        where Install_Date between curdate() - interval 6 day and curdate()
        group by Rep_Name) inst
order by `Sales` desc, `Passed Credit` desc, ..., `Installs` desc

我得到的输出对于第一个表“cust”中的所有字段都是正确的,但我的所有代表都显示在查询的后半部分返回的第一个“安装”计数,无论是 1 还是 20。

它返回的是这样的:

Rep ----- Sales ----- Passed Credit ----- Sales Scheduled ----- Installs
John  |    10     |         7         |         6           |      5
Mike  |    8      |         7         |         6           |      5
Trey  |    8      |         6         |         4           |      5
Drew  |    6      |         3         |         3           |      5
Angel |    3      |         2         |         4           |      5
Total |    35     |         25        |         23          |      22

安装表还包括一些本周没有销售的人,但他们也没有出现在这里,他们应该出现的。理想情况下,表格应该是这样的:

Rep ----- Sales ----- Passed Credit ----- Sales Scheduled ----- Installs
John  |    10     |         7         |         6           |      5
Mike  |    8      |         7         |         6           |      9
Trey  |    8      |         6         |         4           |      4
Drew  |    6      |         3         |         3           |      4
Angel |    3      |         2         |         4           |      0
Tracy |    0      |         0         |         0           |      3
Diego |    0      |         0         |         0           |      1
Total |    35     |         25        |         23          |      26

我尝试了一些疯狂的连接、联合和 where 语句的组合。关于如何获得这个的任何其他想法?任何帮助表示赞赏!

更新 1 感谢 spencer7593,我能够通过使用左连接解决我的“安装”列显示不正确的问题。目前仍在努力显示本周销售额为 0 的代表,但有安装量(来自前几周的销售额)。

我之前忘记包含的所列表格的必要限定字段:

Customers - rep_id, Sale_Date, id, Passed_Credit, Sale_Scheduled
Users - id (which is customers.rep_id), Rep_Name, Rep_Office_Location
Installs - id (which is customers.id), Install_Date, Install_Status

我知道我们的 CRM 数据库是一团糟,不同表上的多个同名列代表不同的事物。它不是我设计的,同时也是我必须忍受的。

【问题讨论】:

    标签: mysql join subquery left-join union


    【解决方案1】:

    您的查询正在生成两个内联视图的笛卡尔积,custinst

    我怀疑你想“匹配”Rep_Name 上的那些。将该逗号连接运算符替换为 LEFT JOIN 关键字,并添加一个 ON 子句以匹配 cust.Repinst.Rep_Name。既然您要返回 WITH ROLLUP,也许您想将它与来自 inst 的总行匹配?

    大多数列引用都是不合格的,因此我们无法分辨哪个表包含哪个列。 (Rep_NameSale_Date 是来自 ss.customers 还是 ss.users?)我建议您限定所有列引用,以帮助未来的读者,并避免稍后在列时出现“歧义列”错误添加到表格中。

    如果你想返回所有Rep_Name,包括那些没有Sales的,那么你可能需要将WHERE子句中的条件移动到ON子句(如果Sale_Date是对users 表中的一列。)

    对哪个表包含哪些列进行一些猜测,并假设Rep_Name 不为空,如下所示:

    SELECT IFNULL(cust.`Rep_Name`,'Total') AS `Rep`
         , cust.`Sales`
         , cust.`Passed Credit`
         , cust.`Sales Scheduled`
         , inst.`Installs`
      FROM ( SELECT cc.`Rep_Name`   AS `Rep_Name`
                  , COUNT(cu.id)    AS `Sales`
                  , ...
                  , COUNT(...)      AS `Sales Scheduled`
               FROM ss.customers cc
               LEFT
               JOIN ss.users cu
                 ON cu.`id` = cc.`rep_id`
                AND cu.`Sale_Date` BETWEEN CURDATE() - INTERVAL 6 DAY AND CURDATE()
              GROUP BY cc.`Rep_Name`
               WITH ROLLUP
            ) cust
      LEFT
      JOIN ( SELECT ic.`Rep_Name`   AS `Rep_Name`
                  , COUNT(ii.id)    AS `Installs`
               FROM ss.customers ic
               LEFT
               JOIN ss.installs ii
                 ON ii.`id` = ic.`id`
                AND ii.`Install_Date` BETWEEN CURDATE() - INTERVAL 6 DAY AND CURDATE()
              GROUP BY ic.`Rep_Name`
               WITH ROLLUP
            ) inst
         ON inst.`Rep_Name` <=> cust.`Rep_Name`
      ORDER
         BY cust.`Rep_Name` IS NOT NULL DESC
          , cust.`Sales` DESC
          , cust.`Passed Credit` DESC
          , ...
          , inst.`Installs` DESC
    

    注意:NULL 值为Rep_Name 的任何行都将“匹配”WITH ROLLUP 总行。看起来您希望总行位于最后,因此我们可以向 ORDER BY 添加一个表达式以使该行位于最后。


    跟进:

    要获得“零”销售计数,请让驱动表为您提供所有 Rep_Name 的列表,并对提供销售的表进行外部连接。

    作为演示,使用不同的表名

    获取所有个销售代表的列表

     SELECT r.rep_id, r.rep_name
       FROM all_reps r
      ORDER BY r.id
    

    要获得所有个销售代表的列表以及任何匹配的“销售”,我们可以使用外连接。注意匹配的条件在外连接的ON子句中,而不是WHERE子句中。

     SELECT r.rep_id
          , r.rep_name
          , s.sale_date
       FROM all_reps r
       LEFT
       JOIN sales s
         ON s.rep_id = r.rep_id
        AND s.sale_date >= TRUNC(NOW()) - INTERVAL 6 DAY
      ORDER BY r.rep_id, s.sale_date
    

    对于在销售中没有任何“匹配”行的代表,我们将取回包含来自r 的列的行。在这些行上,s 中的列将为 NULL。

    请注意,如果我们将s.sale_date 上的谓词(条件)移动到WHERE 子句,则会过滤掉所有s.sale_date 具有NULL 值的行。这将否定连接的“外部性”并使其等同于内部连接。

    【讨论】:

    • 您先生真棒。我很抱歉没有对某些表的列进行限定,并将猜测留给你。但你实际上设法让他们中的大多数是正确的。等我一分钟后,我会用这些信息更新我的原始帖子。左连接正是我所需要的。我仍在努力让那些本周销售额为 0 的销售代表上台。目前正在尝试使用联合将它们添加到输出的底部,因为 sale_date 不是 ss.users 中的参考列。一旦我进一步了解这一点,我会更新你和帖子。
    • 要获得“零”销售计数,请将驱动表设为包含所有 Rep_Name 的表,并对具有相关销售额的表执行 LEFT JOIN。并将销售日期的谓词(条件)放在ON 子句中,而不是WHERE 子句中。
    猜你喜欢
    • 1970-01-01
    • 2016-01-14
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多