2013-02-24 2 views
4

세 개의 SQL 테이블에서 데이터를 조인하려고합니다. INNER JOIN 세 테이블을 사용하여 쿼리를 반환하는 쿼리 및 조건과 일치하는 행의 합

는 다음과 같은 형식으로되어 있습니다 :

고객

╔════════╗ 
║ 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 절을 추가하여 두 날짜 사이의 작업 시간 및 경비 만 반환하도록 지정하려고합니다. 원하는 출력을 얻으려면 쿼리를 변경해야합니까?

답변

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 

UPDATE

╔════════╦═══════════╦═══════════╦══════════════╦══════════════╗ 
║ CLIENT ║ COUNTWORK ║ WORKTOTAL ║ COUNTEXPENSE ║ EXPENSETOTAL ║ 
╠════════╬═══════════╬═══════════╬══════════════╬══════════════╣ 
║ A  ║   2 ║  25 ║   1 ║   10 ║ 
║ B  ║   1 ║  20 ║   1 ║   20 ║ 
║ C  ║   1 ║  10 ║   0 ║   0 ║ 
╚════════╩═══════════╩═══════════╩══════════════╩══════════════╝ 
+0

고마워, 그 작품은 잘. – Nick

+0

당신은 환영합니다': D' –

+0

당신의 질문에 약간의 변경을해야만 월별로 그룹화 한 다음 클라이언트별로 그룹화 한 다음 월별로 주문해야합니다. 나는 당신이 [여기] (http://www.sqlfiddle.com/#!2/fd61b/5)에서 볼 수있는 바이올린에 가본 적이 있지만, 출력은 월이 아닌 클라이언트에 의해 정렬됩니다. 아무것도 제안 할 수 있니? – Nick

0

을 하위 쿼리로 이동할 수 있으므로 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 
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; 

어쩌면이 작업은 상당히 복잡해 보이지만 모든 클라이언트에 대해 하나의 행만 가질 수 있습니다. 어쩌면 그것은 나중에 더 읽기 쉬울 것입니다 ...