2013-12-18 23 views
0

大家好我有一個很長的查詢,我試圖用較少的話來減少它,並嘗試優化它。如何使用2個表優化我的查詢?

這裏是我的查詢:

SET @year := 2013; 
SET @euro := 3.14; 

SELECT 
SUM(IF (CONCAT(@year, '-01') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Jan, 
SUM(IF (CONCAT(@year, '-02') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Feb, 
SUM(IF (CONCAT(@year, '-03') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Mar, 
SUM(IF (CONCAT(@year, '-04') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Apr, 
SUM(IF (CONCAT(@year, '-05') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) May, 
SUM(IF (CONCAT(@year, '-06') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Jun, 
SUM(IF (CONCAT(@year, '-07') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Jul, 
SUM(IF (CONCAT(@year, '-08') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Aug, 
SUM(IF (CONCAT(@year, '-09') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Sep, 
SUM(IF (CONCAT(@year, '-10') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Oct, 
SUM(IF (CONCAT(@year, '-11') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) Nov, 
SUM(IF (CONCAT(@year, '-12') BETWEEN date_format(date_ini, '%Y-%m') AND date_format(date_expired, '%Y-%m'),i.net_insurance * IF (type_money = 2, @euro, 1), 0)) `Dec` 

FROM insurances i 
INNER JOIN policies p ON p.id = i.policy_id 
WHERE (i.initial_date >= p.date_ini 
AND i.final_date <= p.date_expired) 

這裏是我的結果:

JAN  FEB MAR  APR MAY  JUN JUL  AUG SEP  OCT NOV  DEC 
20286 20286 26496 26496 26496 26496 26496 26496 9936 9936 9936 9936 

這裏是我的演示:http://sqlfiddle.com/#!2/074ff/1

請有人可以幫助我嗎?

我真的很感謝您的幫助。

回答

2

以下是您的替代選擇。

由於創建了@sqlvars,這可能會稍微長一些,但它應該有一些幫助。

第一個FROM(創建sqlvars的子查詢)除了創建12個簡單變量,代表每個月Jan-Dec的「dt」日期作爲日期格式,並且我們擺脫了所有完成的字符串連接該日期的每個記錄以及相應的從/到日期。

第二FROM(子查詢的查詢只對有問題的日期範圍內的合格記錄,但同時它的存在,它有計算@euro因素爲最終列名「InsAmount」。

最後,對於合併在一起,簡化了SUM()合計可讀性因素。

SET @euro := 3.14; 

SELECT 
     SUM(IF (@dtJan BETWEEN date_ini AND date_expired, InsAmount, 0)) Jan, 
     SUM(IF (@dtFeb BETWEEN date_ini AND date_expired, InsAmount, 0)) Feb, 
     SUM(IF (@dtMar BETWEEN date_ini AND date_expired, InsAmount, 0)) Mar, 
     SUM(IF (@dtApr BETWEEN date_ini AND date_expired, InsAmount, 0)) Apr, 
     SUM(IF (@dtMay BETWEEN date_ini AND date_expired, InsAmount, 0)) May, 
     SUM(IF (@dtJun BETWEEN date_ini AND date_expired, InsAmount, 0)) Jun, 
     SUM(IF (@dtJul BETWEEN date_ini AND date_expired, InsAmount, 0)) Jul, 
     SUM(IF (@dtAug BETWEEN date_ini AND date_expired, InsAmount, 0)) Aug, 
     SUM(IF (@dtSep BETWEEN date_ini AND date_expired, InsAmount, 0)) Sep, 
     SUM(IF (@dtOct BETWEEN date_ini AND date_expired, InsAmount, 0)) Oct, 
     SUM(IF (@dtNov BETWEEN date_ini AND date_expired, InsAmount, 0)) Nov, 
     SUM(IF (@dtDec BETWEEN date_ini AND date_expired, InsAmount, 0)) `Dec` 
    from 
     (select 
       @dtJan := '2013-01-01', 
       @dtFeb := DATE_ADD(@dtJan, INTERVAL 1 MONTH), 
       @dtMar := DATE_ADD(@dtFeb, INTERVAL 1 MONTH), 
       @dtApr := DATE_ADD(@dtMar, INTERVAL 1 MONTH), 
       @dtMay := DATE_ADD(@dtApr, INTERVAL 1 MONTH), 
       @dtJun := DATE_ADD(@dtMay, INTERVAL 1 MONTH), 
       @dtJul := DATE_ADD(@dtJun, INTERVAL 1 MONTH), 
       @dtAug := DATE_ADD(@dtJul, INTERVAL 1 MONTH), 
       @dtSep := DATE_ADD(@dtAug, INTERVAL 1 MONTH), 
       @dtOct := DATE_ADD(@dtSep, INTERVAL 1 MONTH), 
       @dtNov := DATE_ADD(@dtOct, INTERVAL 1 MONTH), 
       @dtDec := DATE_ADD(@dtNov, INTERVAL 1 MONTH)) sqlvars, 
     (select 
       date_ini, 
       date_expired, 
       i.net_insurance * IF (type_money = 2, @euro, 1) as InsAmount 
      from 
       insurances i 
       INNER JOIN policies p ON i.policy_id = p.id 
      WHERE 
        i.initial_date >= p.date_ini 
       AND i.final_date <= p.date_expired) as QryRecs 
+0

感謝@DRapp,但它是一種優化?因爲我想要更少的代碼=) –

+0

@CarlitosMorales,less code?不一定,但我會考慮對它進行一些定時測試,看看它們的差異。有時候,有一點額外的(比如每個月準備12個變量)和預先收集合格的記錄次數歐元或不費率可以顯着地清除代碼的可讀性......這又會導致更容易的可維護性。 – DRapp

+0

感謝我學到別的東西的方式=) –

1

您正在嘗試執行數據透視查詢,而MySQL不支持這種查詢。正如你所看到的,解決方法變得非常難看,非常快。

您唯一的選擇是切換到支持PIVOT查詢的DBMS,或者在沒有所有條件列邏輯的情況下恢復到傳統的SELECT ... FROM ...查詢,並在客戶端代碼中執行rows-> columns轉換。

+0

應該如何與少言的查詢? –

+0

溝所有那些'總和(IF('位,並有一個簡單的'選擇field_you_want FROM table'。然後使用客戶端代碼將單個行值轉換爲多列數據集。換句話說,將您的查詢 –