当两个表具有相同的外键时合并三个表
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'
你好,我正在制作一些会计软件,允许你存储多个月的交易(存储在 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)
那么你可以使用
LEFT JOIN budgets b
ON c.id = b.category_id
AND b.date = '2019-08'