我正在尝试从三个SQL表中加入数据。
表格格式如下:
客户端
╔════════╗
║ CLIENT ║
╠════════╣
║ A ║
║ B ║
║ C ║
║ D ║
╚════════╝
work_times
╔════════╦══════════╦════════╦════════════╗
║ Client ║ Work ║ Amount ║ Date ║
╠════════╬══════════╬════════╬════════════╣
║ A ║ Web Work ║ 10 ║ 2013-01-12 ║
║ B ║ Research ║ 20 ║ 2013-01-20 ║
║ A ║ Web Work ║ 15 ║ 2013-01-21 ║
║ C ║ Research ║ 10 ║ 2013-01-28 ║
╚════════╩══════════╩════════╩════════════╝
费用
╔════════╦══════════╦════════╦════════════╗
║ Client ║ Item ║ Amount ║ Date ║
╠════════╬══════════╬════════╬════════════╣
║ A ║ Software ║ 10 ║ 2013-01-12 ║
║ B ║ Software ║ 20 ║ 2013-01-20 ║
╚════════╩══════════╩════════╩════════════╝
我想要一个查询,返回每个客户的工作和费用的计数和总和,即:
╔════════╦═══════════╦═══════════╦══════════════╦══════════════╗
║ CLIENT ║ COUNTWORK ║ WORKTOTAL ║ COUNTEXPENSE ║ EXPENSETOTAL ║
╠════════╬═══════════╬═══════════╬══════════════╬══════════════╣
║ A ║ 2 ║ 25 ║ 1 ║ 10 ║
║ B ║ 1 ║ 20 ║ 1 ║ 20 ║
║ C ║ 1 ║ 10 ║ 0 ║ 0 ║
╚════════╩═══════════╩═══════════╩══════════════╩══════════════╝
到目前为止,我有以下内容:
SELECT clients.Client,
COUNT(distinct work_times.id) AS num_work,
COUNT(expenses.id) AS num_expenses
FROM
clients
INNER JOIN work_times ON work_times.Client = clients.Client
INNER JOIN expenses ON expenses.Client = work_times.Client
GROUP BY
clients.Client
这似乎沿着正确的路线,但它跳过了没有费用的客户端,似乎将num_expenses乘以num_work。我还想添加一个WHERE子句来指定只返回两个日期之间的工作时间和费用。我需要对查询进行哪些更改才能获得所需的输出?
答案 0 :(得分:6)
您需要单独计算子查询中的值。最外层查询的WHERE
子句的目的是过滤掉至少在一个表上记录的记录。因此,在这种情况下,Client D
将不会显示在结果列表中。
SELECT a.*,
COALESCE(b.totalCount, 0) AS CountWork,
COALESCE(b.totalAmount, 0) AS WorkTotal,
COALESCE(c.totalCount, 0) AS CountExpense,
COALESCE(c.totalAmount, 0) AS ExpenseTotal
FROM clients A
LEFT JOIN
(
SELECT Client,
COUNT(*) totalCount,
SUM(Amount) totalAmount
FROM work_times
WHERE DATE BETWEEN '2013-01-01' AND '2013-02-01'
GROUP BY Client
) b ON a.Client = b.Client
LEFT JOIN
(
SELECT Client,
COUNT(*) totalCount,
SUM(Amount) totalAmount
FROM expenses
WHERE DATE BETWEEN '2013-01-01' AND '2013-02-01'
GROUP BY Client
) c ON a.Client = c.Client
WHERE b.Client IS NOT NULL OR
c.Client IS NOT NULL
更新
╔════════╦═══════════╦═══════════╦══════════════╦══════════════╗
║ CLIENT ║ COUNTWORK ║ WORKTOTAL ║ COUNTEXPENSE ║ EXPENSETOTAL ║
╠════════╬═══════════╬═══════════╬══════════════╬══════════════╣
║ A ║ 2 ║ 25 ║ 1 ║ 10 ║
║ B ║ 1 ║ 20 ║ 1 ║ 20 ║
║ C ║ 1 ║ 10 ║ 0 ║ 0 ║
╚════════╩═══════════╩═══════════╩══════════════╩══════════════╝
答案 1 :(得分:0)
您可以将group by
移至子查询,这样就不会为每work_time
重复expense
次{。}}。获得子查询后,可以轻松地向两者添加日期过滤器:
SELECT clients.Client
, work_times.cnt AS num_work
, work_times.total AS total_work
, expenses.cnt AS num_expenses
, expenses.total AS total_expenses
FROM clients
LEFT JOIN
(
SELECT Client
, COUNT(DISTINCT id) as cnt
, SUM(Amount) as total
FROM work_times
WHERE Date between '2013-01-01' and '2013-02-01'
GROUP BY
Client
) work_times
ON work_times.Client = clients.Client
LEFT JOIN
(
SELECT Client
, COUNT(DISTINCT id) as cnt
, SUM(Amount) as total
FROM expenses
WHERE Date between '2013-01-01' and '2013-02-01'
GROUP BY
Client
) expenses
ON expenses.Client = clients.Client
答案 2 :(得分:0)
我没有适当的实例在这里进行测试,但我可能会这样开始,然后如果我可以进一步改进查询那么...
select
T1.client,
ce AS 'Count Work',
am AS 'Work Total',
ci AS 'Count Expense',
am2 AS 'Expense Total'
from (
select
client,
count (work) as ce,
sum(amount) as am
FROM
clients
left join work_times
on fk_client=client
group by
fk_client
) T1
left join (
select
client,
count(item) as ci,
sum(amount) as am2
from
clients
left join expenses
on fk_client=client
group by fk_client
) T2
where T1.client=T2.client;
也许这看起来很复杂,但它确保每个客户只有一行。也许以后它更具可读性......