簡體   English   中英

使用三個表的INNER JOIN查詢可返回符合條件的行數和總和

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM