2013-02-05 67 views
1

我有兩個查詢,如下所示。查詢選擇相同的表格,但具有不同的條件和列數。我無法解決如何結合這些;有什麼辦法嗎?結合不同的SQL查詢

第一個查詢是:

SELECT b.centerBranchNumber, 
     b.countryCode, 
     a.type, 
     SUM(DECODE(a.status, 1, 1, 0)) filled 
    FROM tableA a, 
     tableB b 
WHERE a.branchCode = b.branchCode 
    AND a.registerNumber IN (SELECT c.registerNumber 
           FROM tableC c 
          WHERE c.registerDate <= '01.02.2013' 
           AND c.state = 'A' 
           AND c.contractState != 2) 
GROUP BY b.centerBranchNumber, 
      b.countryCode, 
      a.type; 

結果是這樣的:

BranchNumber  CountryCode Type Filled 
1452     USA   0 5 
1452     USA   2 8 
1452     USA   1 16 
7854     GER   0 10 
7854     GER   1 3 

第二個查詢是:

SELECT b.centerBranchNumber, 
     b.countryCode, 
     a.type, 
     SUM(DECODE(a.status, 0, 1, 0)) free, 
     SUM(DECODE(a.status, 2, 1, 0)) damaged  
    FROM tableA a, 
     tableB b 
WHERE a.kks_kayitdrm = 'A'  
    AND a.branchCode = b.branchCode  
    AND a.recordDate <= '01.02.2013' 
GROUP BY b.centerBranchNumber, 
      a.type, 
      b.countryCode; 

,其結果是:

BranchNumber  CountryCode Type Free  Damage 
1452     USA   0 5  2 
1452     USA   2 8  1 
1452     USA   1 16  5 
7854     GER   0 10  9 
7854     GER   1 3  16 

如果我結合,我想如下結果:

BranchNumber  CountryCode Type Filled Free  Damage 
1452     USA   0  1   5  2 
1452     USA   2  2   8  1 
1452     USA   1  65  16  5 
7854     GER   0  7   10  9 
7854     GER   1  45  3  16 

回答

1

你的第一個查詢可以被改寫爲:

SELECT b.centerBranchNumber, 
     b.countryCode, 
     a.type, 
     SUM(DECODE(a.status, 1, 1, 0)) filled 
    FROM tableA a 
    JOIN tableB b 
    ON a.branchCode = b.branchCode 
    JOIN tableC 
    ON a.registerNumber = c.registerNumber 
WHERE c.registerDate <= '01.02.2013' 
    AND c.state = 'A' 
    AND c.contractState != 2 
GROUP BY b.centerBranchNumber, 
      b.countryCode, 
      a.type 

至於你的第二個到ANSI語法以及(它將幫助更復雜的查詢,因爲當你做錯了事情時,這是非常明顯的)它變成這樣:

SELECT b.centerBranchNumber, 
     b.countryCode, 
     a.type, 
     SUM(DECODE(a.status, 0, 1, 0)) free, 
     SUM(DECODE(a.status, 2, 1, 0)) damaged  
    FROM tableA a 
    JOIN tableB b 
    ON a.branchCode = b.branchCode  
WHERE a.kks_kayitdrm = 'A' 
    AND a.recordDate <= '01.02.2013' 
GROUP BY b.centerBranchNumber, 
      a.type, 
      b.countryCode 

正如你所看到的兩個查詢之間存在大量的相似性。爲了得到你想要的結果集,有兩種方法。將不相似的條件移入SUM中的CASE語句。或者,你可以聯合所有這兩個查詢在一起,再次總結。我寧願使用CASE語句,因爲您減少了必須完成的工作量;缺點是查詢變得不太容易閱讀。

查詢的公共部分是:

SELECT b.centerBranchNumber, 
     b.countryCode, 
     a.type 
    FROM tableA a 
    JOIN tableB b 
    ON a.branchCode = b.branchCode 
GROUP BY b.centerBranchNumber, 
      a.type, 
      b.countryCode 

以此爲直到你得到相同的結果,你可以慢慢地添加到它的基地。您必須記住將相同的條件添加到WHERE/JOINS以確保您獲得相同的結果。

如果我們首先添加所有條件;您必須將第一個查詢中tableC上的JOIN更改爲LEFT OUTER JOIN。這與WHERE子句將結果集限制爲INNER JOIN完全相同。

SELECT b.centerBranchNumber, 
     b.countryCode, 
     a.type 
    FROM tableA a 
    JOIN tableB b 
    ON a.branchCode = b.branchCode 
    LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber 
WHERE c.registerDate <= '01.02.2013' 
    AND c.state = 'A' 
    AND c.contractState != 2 
GROUP BY b.centerBranchNumber, 
      b.countryCode, 
      a.type 

添加條件,你現在需要一個或您的WHERE子句中的第二個查詢:

SELECT b.centerBranchNumber, 
     b.countryCode, 
     a.type 
    FROM tableA a 
    JOIN tableB b 
    ON a.branchCode = b.branchCode 
    LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber 
WHERE (c.registerDate <= '01.02.2013' 
     AND c.state = 'A' 
     AND c.contractState != 2 
      ) 
    OR (a.kks_kayitdrm = 'A' 
     AND a.recordDate <= '01.02.2013' 
      ) 
GROUP BY b.centerBranchNumber, 
      b.countryCode, 
      a.type 

接下來,您的日期似乎比多了幾分陌生。您似乎沒有將字符串文字'01.02.2013'轉換爲日期,因爲它不是YYYYMMDD形式,所以您的比較不起作用。您所依靠的NLS_DATE_FORMAT的形式爲DD.MM.YYYY,您無法保證每次會話都能保證。要比較一個日期,您應該使用內置的TO_DATE()函數以及相應的format model或ANSI datetime literal進行明確轉換,我在this answer中對此進行了更全面的說明。

只想說,甲骨文explicitly recommends against using implicit conversion因爲:

  • SQL語句是容易當你使用顯式數據類型轉換函數理解。

  • 隱式數據類型轉換可能會對性能產生負面影響,尤其是如果將列值的數據類型轉換爲常數而非其他方式。

  • 隱式轉換取決於它發生的上下文,並且在每種情況下可能不會以相同的方式工作。例如,從日期時間值到VARCHAR2值的隱式轉換可能會返回意外的一年,具體取決於NLS_DATE_FORMAT 參數的值。

  • 隱式轉換的算法可能會在軟件版本和Oracle產品之間發生變化。顯式轉換的行爲更具可預測性。

要比較你的日期,因此我會建議使用TO_DATE(),例如:

WHERE (c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy') 

最後,我們可以在增加的款項;這意味着重複您之前的條件。您可以簡化爲您的第一個查詢,因爲是否填充「是完全依賴於左外部連接,這意味着如果JOIN中該表的registerNumber不是null,則條件爲真。

在這兩種情況下,我都使用CASE語句而不是DECODE;這是因爲CASE功能更強大,並且執行正確的數據類型which is not guaranteed with DECODE

把所有這一起最終的查詢變爲:

SELECT b.centerBranchNumber 
    , b.countryCode 
    , a.type 
    , sum(case when a.status = 1 and c.registernumber is not null then 1 
       else 0 
      end) as filled 
    , sum(case when a.status = 0 
        and a.kks_kayitdrm = 'A' 
        and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy') 
        then 1 
       else 0 
      end) as free 
    , sum(case when a.status = 2 
        and a.kks_kayitdrm = 'A' 
        and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy') 
        then 1 
       else 0 
      end) as damaged 
    FROM tableA a 
    JOIN tableB b 
    ON a.branchCode = b.branchCode 
    LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber 
WHERE (c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy') 
     AND c.state = 'A' 
     AND c.contractState != 2 
      ) 
    OR (a.kks_kayitdrm = 'A' 
     AND a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy') 
      ) 
GROUP BY b.centerBranchNumber 
     , b.countryCode 
     , a.type 

您可以使用此方法更一般的查詢相結合,它是適當的。

+0

,非常感謝你的回答。你的asnwer很棒:) – engcmreng