获取按用户分组的总成本

Getting Total Cost Grouped by User

我已经为这个查询苦苦挣扎了两天。我有一个 user table 有一些值与 order table (用户可以有多个订单)。这个table和order_item有关系(订单可以有多个orderItems)。 Order_Item 与 invoice 有关系(order_item 可以有多个发票。

分店和店铺与用户是一对一的关系

以下是所有 table 中最重要的值:

user:
-userId (int)

order
-orderId (int)
-userId (int)
-inserted (date)

order_item
-orderItemId (int)
-orderId (int)

invoice
-invoiceId (int)
-orderItemId (int)
-cost (double)

外键在这里是不言自明的。用户->订单->订单项->发票。 我需要的是一个查询,其中结果中的每一行代表一个用户,其中两列代表 2014 年和 2015 年的总销售额(成本总和)。

所以它要做的是在一行中向每个用户显示来自用户 table 的一些信息(公司名称、电子邮件等)和两列 2014 年的总成本和 1 2015 年基于 order.inserted 日期值。

例如:

姓名: |电子邮件 | 2014 成本 | 2015 成本

Google |信息@google.com | 50.000 欧元 | 45.000 欧元

现在我已经得到了第一个总和的结果(显示所有用户而不考虑成本),只有当我第二次加入时(计算 2015 年的成本)我以前的总和成本完全搞砸了。

我在联接中尝试了一些 select 查询,但无法使任何查询正常工作。我并不是 SQL 的完全初学者,但这对我来说太复杂了,无法弄清楚这个确切的时刻。

这是我用来获取 2014 年结果的查询(一旦我为 2015 年添加第二个连接,它就会搞砸):

SELECT t.userId, SUM(i.cost),
t.companyName, t.email,
t.website, t.tel, t.priority,
b.name AS Branch, s.name AS `Shop Name` 
FROM `user` AS t
LEFT JOIN branch AS b ON b.branchId = t.branchId
LEFT JOIN shop AS s ON s.shopId = t.shopId
LEFT JOIN `order` AS o ON (o.userId = t.userId AND YEAR(o.inserted) = 2014) 
LEFT JOIN order_item AS oi ON oi.orderId = o.orderId
LEFT JOIN invoice AS i ON i.orderItemId = oi.orderItemId 
GROUP BY t.userId

我真的希望有人能帮我解决这个问题。 (我在 Navicat 8 中使用 mySQL/innoDB)。

最终,这是您尝试生产的 枢轴 table 的一种形式。您可以将条件直接放在 SUM() 聚合中,而不是在联接的 ON 子句中加入和测试年份条件,例如:

-- If the year matches, add the cost value into the sum
-- Otherwise, add zero
SUM(CASE WHEN YEAR(o.inserted) = 2014 THEN i.cost ELSE 0 END) AS `2014 Cost`

这消除了对这些额外连接的需要。在应用 GROUP BY 时,它应该包括所有可能在每个组中不同的列。 MySQL 允许您从 GROUP BY 中省略 SELECT 中的列,其中大多数其他 RDBMS 会导致查询编译错误。

SELECT 
  t.userId,
  -- Apply the aggregate SUM() conditionally for each year
  SUM(CASE WHEN YEAR(o.inserted) = 2014 THEN i.cost ELSE 0 END) AS `2014 Cost`
  SUM(CASE WHEN YEAR(o.inserted) = 2015 THEN i.cost ELSE 0 END) AS `2015 Cost`
  t.companyName,
  t.email,
  t.website,
  t.tel,
  t.priority,
  b.name AS Branch,
  s.name AS `Shop Name` 
FROM 
  `user` AS t 
  LEFT JOIN branch AS b ON b.branchId = t.branchId
  LEFT JOIN shop AS s ON s.shopId = t.shopId
  LEFT JOIN `order` AS o ON (o.userId = t.userId) 
  LEFT JOIN order_item AS oi ON oi.orderId = o.orderId
  LEFT JOIN invoice AS i ON i.orderItemId = oi.orderItemId 
GROUP BY 
  t.userId,
  -- Adding remaining SELECT fields
  -- though MySQL will allow these to be omitted
  -- without breaking this particular query
  t.companyName,
  t.email,
  t.website,
  t.tel,
  t.priority,
  Branch,
  `Shop Name`