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

时间:2019-08-31 15:29:51

标签: mysql join foreign-keys relational-database primary-key

您好,我正在制作一些会计软件,该软件可让您跨月存储交易(存储在表transactions中),并根据可用类别列表对这些交易进行分类(存储在表categories中) 。最终,用户每个月都可以创建预算,在该预算中,他们可以建立列表(来自categories的子集),并为每个条目分配目标。这些列表存储在表budget中。

Table Relationship

我需要一个查询,该查询返回指定月份的支出和预算摘要。该摘要将是类别,名称,预算,目标和sum(transactions.amount)的表格。

Expected Result

有时,用户会有指定月份的预算项目,但尚未进行该类别的任何交易(“吃饭”示例)。有时,用户会有一笔他们没有预算的意外支出(“汽车维修示例”),并且在某些类别(例如度假)中,用户没有对该项目进行预算,并且没有该类别的支出。

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;

让我得到了我想要的另一半。是否有单个查询可以返回如上图所示的结果?如果我们排除目标和总和均为NULL的结果,我会更加兴奋。

2 个答案:

答案 0 :(得分:1)

如果您知道每个类别和每个月最多有一个预算,则可以(左)将两个(子)表加入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表中强制类别和月份组合的唯一性,我将创建一个虚拟列,如

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

(category_id, year_month)上的唯一键

然后您就可以使用

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

答案 1 :(得分:0)

您可以尝试在下面的查询中找到合适的结果:

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;

谢谢。