2012-08-17 64 views
0

我有兩個問題。 First:我想將兩個查詢合併爲一個放入存儲過程進行報告製作。他們是SQL在組合兩個查詢後得到不同結果

查詢1

SELECT T0.Name AS Period, SUM(ISNULL(T2.LineTotal, 0)) AS CurrentDebtors, MAX(T1.DocRate) AS ExchangeRate, 
SUM(CASE WHEN DATEDIFF(day, T1.DocDate, T1.DocDueDate) > 30 
THEN T2.LineTotal END) AS NonCurrentDebtors 
FROM OFPR T0 LEFT OUTER JOIN OINV T1 ON T0.AbsEntry = T1.FinncPriod 
INNER JOIN INV1 T2 ON T1.DocEntry = T2.DocEntry WHERE YEAR(T1.DocDate) = @Year 
GROUP BY T0.Name 
ORDER BY T0.Name 

查詢2

SELECT T0.Name AS Period, SUM(T1.DocTotal) AS TurnoverMonth 
FROM dbo.OFPR T0 LEFT OUTER JOIN dbo.ORCT T1 ON T0.AbsEntry = T1.FinncPriod 
WHERE YEAR(T1.DocDate) = @Year 
GROUP BY T0.Name 
ORDER BY T0.Name 

我讓他們組合成這樣:

SELECT T0.Name AS Period, SUM(ISNULL(T2.LineTotal, 0)) AS CurrentDebtors, MAX(T1.DocRate) AS ExchangeRate, 
SUM(CASE WHEN DATEDIFF(day, T1.DocDate, T1.DocDueDate) > 30 
THEN T2.LineTotal END) AS NonCurrentDebtors , SUM(ISNULL(T3.DocTotal, 0)) AS TurnoverMonth 
FROM OFPR T0 LEFT OUTER JOIN OINV T1 ON T0.AbsEntry = T1.FinncPriod 
INNER JOIN INV1 T2 ON T1.DocEntry = T2.DocEntry 
JOIN ORCT T3 ON T0.AbsEntry = T3.FinncPriod 
WHERE YEAR(T1.DocDate) = @Year 
GROUP BY T0.Name 
ORDER BY T0.Name 

的問題是,儘管分開2個查詢結果上面的內容是正確的,上面的組合查詢返回了數量非常大的錯誤值。我如何正確地結合這兩者? Second:如果存在非常大的數據,查詢1還需要一些時間才能執行,以何種方式來提高其效率?使用Microsoft SQL Server 2008

回答

2

由於連接的性質,如果您嘗試同時聚合兩個或多個表,您必然會得到重複的聚合。通過TO連接時,T2和T3之間可能存在n:m關係。爲了解決這個問題,你可以使用cte或派生表 - 這個重寫使用派生表T3來根據TO.AbsEntry檢索一行,從而消除重複。

SELECT T0.Name AS Period, 
     SUM(T2.LineTotal) AS CurrentDebtors, 
     MAX(T1.DocRate) AS ExchangeRate, 
     SUM(CASE WHEN DATEDIFF(day, T1.DocDate, T1.DocDueDate) > 30 
       THEN T2.LineTotal 
      END) AS NonCurrentDebtors, 
     T3.TurnoverMonth 
    FROM OFPR T0 
INNER JOIN OINV T1 
    ON T0.AbsEntry = T1.FinncPriod 
INNER JOIN INV1 T2 
    ON T1.DocEntry = T2.DocEntry 
INNER JOIN 
(
    SELECT ORCT.FinncPriod, 
      SUM(ORCT.DocTotal) AS TurnoverMonth 
     FROM ORCT 
    WHERE YEAR(ORCT.DocDate) = @Year 
    GROUP BY ORCT.FinncPriod 
) T3 
    ON T0.AbsEntry = T3.FinncPriod 
WHERE YEAR(T1.DocDate) = @Year 
GROUP BY T0.Name, T3.TurnoverMonth 
ORDER BY T0.Name 

另一種可能性是您需要按年過濾ORCT表,這在聯合查詢中省略。對於你可能會考慮擴大該過濾器日期範圍測試性能的原因,以允許SQL Server上DocPeriod使用索引:

where DocDate >= convert(datetime, convert(varchar(20), @year) + '0101') 
    and DocDate < dateadd (year, 1, 
         convert(datetime, convert(varchar(20), @year) + '0101')) 

說明我已經加入到TurnoverMonth組。這不會改變任何事情,因爲每個T3將會有一行存在。

我也從sum中刪除了isnull()test,因爲無論如何都會從sum()中刪除null值。如果要用零替換最終的空結果,則在isnull()中包含sum()。

編輯:忘了提及我已經改變了左連接到內部連接,因爲T1上的條件改變了連接到內部連接的意義(缺少的行不能被任何東西匹配,除非爲空/不爲空)。如果實際需要外連接,請將條件移至ON子句。

+0

感謝NikolaMarkovinović。這對我有很大的幫助。 – 2012-08-17 11:50:54

+0

@KinyanjuiKamau不客氣:-) – 2012-08-17 11:51:52