[英]INNER JOIN query using three tables to return Count and Sum of rows that match criteria
我正在嘗試從三個SQL表中加入數據。
這些表的格式如下:
客戶
╔════════╗
║ CLIENT ║
╠════════╣
║ A ║
║ B ║
║ C ║
║ D ║
╚════════╝
工作時間
╔════════╦══════════╦════════╦════════════╗
║ 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子句以指定僅返回兩個日期之間的工作時間和費用。 為了獲得所需的輸出,我需要對查詢進行哪些更改?
您需要在子查詢中單獨計算值。 最外層查詢的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 ║
╚════════╩═══════════╩═══════════╩══════════════╩══════════════╝
您可以將group by
移動到子查詢,這樣就不會為每次expense
重復每個work_time
。 一旦有了子查詢,就可以輕松地將日期過濾器添加到兩個查詢中:
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
我沒有合適的實例在這里進行測試,但是我可能會先這樣做,然后再檢查一下是否可以進一步改善查詢條件...
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;
也許這看起來很復雜,但是可以確保每個客戶只有一行。 也許以后更易讀...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.