【问题标题】:Calculating values in a hierarchy of a known depth在已知深度的层次结构中计算值
【发布时间】:2014-01-16 08:35:35
【问题描述】:

我必须从 2 个表中查询一些派生值。它们的简化结构如下:

用户

用户有一个 ID 和一个父列,该列表示其父级的 ID。每个用户还有一个佣金值,表示他们从他们的员工那里获得的销售额的百分比。

只有员工才能进行销售,该信息记录在下表中

+------------------------------------+
| ID Name          Parent Commission |
+------------------------------------+
| 1  SeniorManager NULL   5          |
| 2  Manager       1      10         |
| 3  Employee1     2      13         |
| 4  Employee2     2      12         |
+------------------------------------+

销售

此表记录通过 ID 链接的员工的销售额。它记录销售金额以及销售时间。

+---------------------------+
| user_id amount created_at |
+---------------------------+
| 3       100    2014-01-16 |
| 3       120    2014-01-16 |
| 3       110    2014-01-16 |
+---------------------------+

从系统的其他部分,我知道给定用户 ID 的用户的深度。在实际系统中,有 7 个固定级别,但为了问题,我在这里对其进行了简化。

我要写的查询是:给定 SeniorManager 的 ID 和日期范围,显示他下面的经理列表、这些经理的汇总佣金以及该经理的预期佣金。因此,鉴于上述数据,人们会期望:

+--------------------------------------------+
| Name    Sales ManagerCommission Commission |
+--------------------------------------------+
| Manager 330   33.30             16.65      |
+--------------------------------------------+

到目前为止我的查询是:

SELECT
    users.name AS Name,
    SUM(sales.amount) AS Sales,
    SUM(sales.amount) * (users.commission/100) AS ManagerCommission
FROM
    users
LEFT JOIN users AS employees
    ON employees.parent = users.id
LEFT JOIN sales
    ON sales.id = employees.id AND
    sales.created_at BETWEEN DATE(?) AND DATE(?)
WHERE
    users.parent = ?
GROUP BY
    users.name

我不确定如何获得按经理而不是员工分组的佣金的最后一列值。另外作为一个附带问题,有没有办法重用在 select 语句中使用两次的SUM(sales.amount)。我宁愿不计算完全相同的值两次。我计划为每个已知深度编写 7 个查询。有没有更有效的方法来做到这一点?

【问题讨论】:

  • 您用于存储分层数据的模型称为“邻接表”。可悲的是,MySQL 不支持递归函数,因此使用这样的模型必须为希望遍历的层次结构的每个级别进行自连接——但很明显,这不是一个非常可扩展的解决方案。更好的建议是使用嵌套集或图表的传递闭包表来重构数据。
  • 对于非常有限的数据集,您的查询应该没问题,但我认为您需要检查 WHERE 子句中的 users.ID 而不是 users.parent。
  • @eggyal 假设我无法更改数据建模的方式(我不是这个项目的唯一开发人员),使用应用程序代码而不是这样做更有意义吗?寻求 SQL 解决方案?
  • @Kickstart,一个高级经理下可以有多个经理,所以在这种情况下,我会把有问题的高级经理的ID和父级查询,这样我就可以得到所有的子经理而不仅仅是一名高级经理

标签: mysql sql


【解决方案1】:

为每个管理级别添加一个联接:-

SELECT
    senior_manager.name AS Name,
    SUM(sales.amount) AS Sales,
    SUM(sales.amount * manager.commission/100) AS ManagerCommission,
    SUM(sales.amount) * (senior_manager.commission/100) AS SeniorManagerCommission
FROM
    users AS senior_manager
LEFT JOIN users AS manager
    ON manager.parent = senior_manager.id
LEFT JOIN users AS employees
    ON employees.parent = manager.id
LEFT JOIN sales
    ON sales.id = employees.id AND
    sales.created_at BETWEEN DATE(?) AND DATE(?)
WHERE
    senior_manager.id = ?
GROUP BY
    senior_manager.name

它的 SQL 小提琴:-

http://www.sqlfiddle.com/#!2/2cfffe/4

【讨论】:

    猜你喜欢
    • 2021-09-11
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多