当两个表具有相同的外键时合并三个表

Combining three tables when two have the same foreign key

你好,我正在制作一些会计软件,允许你存储多个月的交易(存储在 table transactions 中)并根据可用类别列表(存储在 transactions 中对这些交易进行分类=40=] categories)。最后,每个月用户都可以创建预算,在其中构建列表(来自 categories 的子集)并为每个条目分配目标。这些列表存储在 table budget 中。

我需要一个 return 指定月份的支出和预算摘要的查询。此摘要将是 categories.name、budget.goal 和 sum(transactions.amount).

的 table

有时,用户会有指定月份的预算项目,但尚未对该类别进行任何交易(Out to Eat 示例)。有时用户会有一笔他们没有预算的意外费用(汽车维修示例),并且会有一些类别(如假期)用户没有为该项目预算并且没有该类别的费用。

SELECT categories.id, categories.name, SUM(transactions.amount) FROM categories LEFT JOIN transactions ON categories.id=transactions.category_id WHERE transactions.date LIKE '2019-08-%' GROUP BY categories.id;

得到我想要的一半

SELECT categories.id, categories.name, budgets.goal FROM categories LEFT JOIN budgets ON categories.id=budgets.category_id WHERE budgets.date LIKE '2019-08-%' GROUP BY categories.id;

得到我想要的另一半。是否有一个查询可以 return 结果如上图所示?如果我们可以排除 goal 和 sum 均为 NULL 的结果,我会更加兴奋。

您可以尝试以下查询以找到正确的结果:

SELECT c.name,b.goal,sum(ct.amount) FROM era.categories c left join budget b on b.cat_id=c.id left join transactions ct on ct.cat_id=c.id WHERE b.date LIKE '2019-08-%' group by ct.cat_id;

谢谢。

如果您知道每个类别和每个月最多可以有一个预算,那么您可以(左)加入两个(child)tables 到 categories

SELECT 
  c.id,
  categories.name,
  MAX(b.goal) as budget_goal,
  SUM(t.amount) as total_txn_amount
FROM categories c
LEFT JOIN budgets b
  ON  c.id = b.category_id 
  AND b.date LIKE '2019-08-%'
LEFT JOIN transactions t
  ON c.id = t.category_id 
GROUP BY categories.id
HAVING COALESCE(budget_goal, total_txn_amount) IS NOT NULL;

请注意,虽然我们知道每个组只能有一个预算,但引擎不会,并且可能会声称 b.goal 必须在 GROUP BY 子句中或在聚合函数中使用。所以我们使用 MAX(b.goal) 来避免这个错误。

为了提高第一个 JOIN 的性能,我会更改

AND b.date LIKE '2019-08-%'

AND b.date >= '2019-08-01'
AND b.date <  '2019-08-01' + INTERVAL 1 MONTH

并在 (category_id, date) 上创建复合索引。

同时为了在 budgets table 中强制类别和月份组合的唯一性,我会创建一个虚拟列,如

year_month VARCHAR(7) as (LEFT(date, 7))

(category_id, year_month)

上的 UNIQUE KEY

那么你可以使用

LEFT JOIN budgets b
  ON  c.id = b.category_id 
  AND b.date = '2019-08'