2013-07-10 32 views
1

我有3張桌子;合同,經銷商和用戶。MySQL將多個子查詢優化爲嵌套的內部連接?

用戶有很多經銷商和經銷商有很多合同,但合同不直接與用戶關聯。

我正在嘗試構建一份報告,讓我每月統計用戶在過去12個月中分組的完成合同。

到目前爲止,我已經建立了多個子查詢,這是非常緩慢:SQL Fiddle

SELECT *, 
    (SELECT count(*) FROM contracts 
    WHERE 
     dealer_id IN 
     (SELECT id FROM dealers WHERE user_id = User.id) 
     AND status = 'Paid' 
     AND completion_date BETWEEN 
     '2012-08-01 00:00:00' AND '2012-08-31 23:59:59' 
) AS Aug_2012, 

    (SELECT count(*) FROM contracts 
    WHERE 
     dealer_id IN 
     (SELECT id FROM dealers WHERE user_id = User.id) 
     AND status = 'Paid' 
     AND completion_date BETWEEN 
     '2012-09-01 00:00:00' AND '2012-09-30 23:59:59' 
) AS Sep_2012 
FROM users AS User 
    WHERE 
    id IN(SELECT user_id FROM dealers WHERE active = 1 AND user_id IS NOT NULL GROUP BY user_id) 
    AND id != 1 
    ORDER BY User.name ASC 

而是它選擇每個月我想使用像這樣的子查詢:

COUNT(*) as last_12_months, 
SUM(case when MONTH(completion_date) = 8 then 1 else 0 end) as Aug_2012, 
SUM(case when MONTH(completion_date) = 9 then 1 else 0 end) as Sep_2012, 
etc. 

由於我會返回多列,我將不得不重組它,但我不知道如何。如果我使用INNER JOIN,我會加入哪個子句?

下面是基於以下米哈伊爾的答案最終查詢:

SELECT 
User.*, 
SUM(case when MONTH(completion_date) = 8 then 1 else 0 end) AS Aug_2012, 
SUM(case when MONTH(completion_date) = 9 then 1 else 0 end) AS Sep_2012, 
SUM(case when MONTH(completion_date) = 10 then 1 else 0 end) AS Oct_2012, 
SUM(case when MONTH(completion_date) = 11 then 1 else 0 end) AS Nov_2012, 
SUM(case when MONTH(completion_date) = 12 then 1 else 0 end) AS Dec_2012, 
SUM(case when MONTH(completion_date) = 1 then 1 else 0 end) AS Jan_2013, 
SUM(case when MONTH(completion_date) = 2 then 1 else 0 end) AS Feb_2013, 
SUM(case when MONTH(completion_date) = 3 then 1 else 0 end) AS Mar_2013, 
SUM(case when MONTH(completion_date) = 4 then 1 else 0 end) AS Apr_2013, 
SUM(case when MONTH(completion_date) = 5 then 1 else 0 end) AS May_2013, 
SUM(case when MONTH(completion_date) = 6 then 1 else 0 end) AS Jun_2013, 
SUM(case when MONTH(completion_date) = 7 then 1 else 0 end) AS Jul_2013, 
SUM(case when completion_date BETWEEN '2012-08-01 00:00:00' AND '2013-07-31 23:59:59' then 1 else 0 end) as last_12_months 
FROM users AS User 
LEFT OUTER JOIN 
( 
    SELECT id, user_id FROM dealers 
    WHERE active = 1 AND user_id IS NOT NULL 
) AS Dealer ON User.id = Dealer.user_id 
LEFT OUTER JOIN 
(
    SELECT completion_date, status, dealer_id FROM contracts 
    WHERE completion_date BETWEEN '2012-08-01 00:00:00' AND '2013-07-31 23:59:59' AND status = 'Paid' AND cancelled = 0 
) AS Contract on Dealer.id = Contract.dealer_id 
WHERE 
    User.id IN 
    (
     SELECT user_id FROM dealers 
     WHERE active = 1 AND user_id IS NOT NULL 
     GROUP BY user_id 
    ) 
GROUP BY 
    User.id order by User.name asc 

這是快約4倍。

回答

2

試試這個:

select 
    User.id, User.name, 
    sum(case when MONTH(completion_date) = 8 and Year(completion_date)=2012 then 1 else 0 end) as Aug_2012, 
    sum(case when MONTH(completion_date) = 9 and Year(completion_date)=2012 then 1 else 0 end) as Sep_2012, 
    sum(case when MONTH(completion_date) = 10 and Year(completion_date)=2012 then 1 else 0 end) as Oct_2012, 
    sum(case when MONTH(completion_date) = 11 and Year(completion_date)=2012 then 1 else 0 end) as Nov_2012, 
    sum(case when MONTH(completion_date) = 12 and Year(completion_date)=2012 then 1 else 0 end) as Dec_2012, 
    sum(case when MONTH(completion_date) = 1 and Year(completion_date)=2013 then 1 else 0 end) as Jan_2012, 
    sum(case when MONTH(completion_date) = 2 and Year(completion_date)=2013 then 1 else 0 end) as Feb_2012, 
    sum(case when MONTH(completion_date) = 3 and Year(completion_date)=2013 then 1 else 0 end) as Mar_2012, 
    sum(case when MONTH(completion_date) = 4 and Year(completion_date)=2013 then 1 else 0 end) as Apr_2012, 
    sum(case when MONTH(completion_date) = 5 and Year(completion_date)=2013 then 1 else 0 end) as May_2012, 
    sum(case when MONTH(completion_date) = 6 and Year(completion_date)=2013 then 1 else 0 end) as Jun_2012, 
    sum(case when MONTH(completion_date) = 7 and Year(completion_date)=2013 then 1 else 0 end) as Jul_2012 
from users AS User 
left outer join dealers on 
    User.id=dealers.user_id 
left outer join contracts on 
    dealers.id=contracts.dealer_id 
group by 
    User.id, 
    contracts.status 
having 
    contracts.status='Paid' 
order by 
    User.name asc; 
+0

謝謝,這讓我在正確的方向。 –