2013-07-14 37 views
0

我有以下聲明:過濾行只

SELECT 
    (CONVERT(VARCHAR(10), f1, 120)) AS ff1, 
    CONVERT(VARCHAR(10), f2, 103) AS ff2, 
    ..., 
    Bonus, 
    Malus, 
    ClientID, 
FROM 
    my_table       
WHERE 
    <my_conditions> 
ORDER BY 
    f1 ASC 

這個select返回幾行對每個客戶端ID。我必須過濾掉所有沒有非空Bonus或Malus的行的客戶。

我怎樣才能做到這一點通過改變這個選擇由一個語句只沒有複製所有這些選擇

我可以將結果存儲在#temp_table中,然後對數據進行分組並使用分組的結果來過濾臨時表。 - 但我應該只用一個陳述來做

我可以執行此選擇兩次 - 一次分組,然後我可以根據分組結果過濾行。 但我不想選兩次

可能CTE(公共表表達式)可能僅執行選擇一次在這裏有用和能夠使用結果進行分組,然後選擇基礎上的分類結果期望的結果。

這個問題的更優雅的解決方案?

預先感謝您!

只是爲了澄清的SQL應該怎麼做我補充一個例子:

ClientID Bonus Malus 
1   1  
1     
1    1 
2     
2     
3   4  
3    5 
3   1  

因此,在這種情況下,我不希望客戶端ID = 2行出現(他們不感興趣)。結果應該是:

ClientID Bonus Malus 
1   1  
1     
1    1 
3   4  
3    5 
3   1  
+3

*我不得不過濾掉所有與客戶端的行沒有與非空的獎金或蘋果的任何行。*你可以換一種說法你想要什麼,而不是要你不想要?我從這句話中得到了令人頭痛的問題:) –

+0

對不起:)。我將添加一個示例來更好地解釋它 – Alexander

+0

完成。問題中有一個例子。請讓我知道是否需要更多的說明。 – Alexander

回答

0
SELECT Bonus, 
     Malus, 
     ClientID 
FROM my_table       
WHERE ClientID not in 
(
    select ClientID 
    from my_table 
    group by ClientID 
    having count(Bonus) = 0 and count(Malus) = 0 
) 
+0

這正是我不想做的事情(請看我的問題中的粗體文本) - 選擇它兩次(我有很多複雜的條件在我的「哪裏」) – Alexander

+0

您的複雜條件只需要在外部選擇。內部選擇只有一個having子句。 –

0

的CTE將正常工作,但實際上它的內容將被執行兩次,因爲他們被克隆到其中正在使用的CTE的所有地方。與使用臨時表相比,這可能是淨贏得或者損失的表現。如果查詢非常昂貴,它可能會成爲損失。如果它很便宜或者許多行正在返回,臨時表將失去比較。

哪種解決方案更好?查看執行計劃並衡量性能。

CTE是更容易,更易於維護的替代方案。

+0

我不知何故有CTE的感覺。他們r不只是好,他們是輝煌的,更快一些50倍以上的自連接,更快的幾個100倍光標..和IM不誇大有關性能..我的大拇指將是CTE即使克隆兩次。 。比下一個最好的選擇 – user1974729

+1

@ user1974729他們執行相同的對您通過手動複製CTE的定義,它是用於所有地方得到查詢速度還是25倍。 SQL Server在內部完成。通常這是你想要的:) – usr

0

您尚未指定Bonus和Malus列的數據類型。所以如果它們是整數(或者可以轉換爲整數),那麼下面的查詢應該是有幫助的。它爲每個ClientID計算兩列的總和。這些總和對於同一個客戶端的每個細節行都是相同的,所以我們可以在WHERE條件下使用它們。聲明SUM() OVER()被稱爲「窗口函數」,不能在WHERE子句中使用,所以我不得不僅僅因爲語法而將您的選擇列表與父列表包裝在一起。

SELECT * 
FROM (
    SELECT 
     CONVERT(VARCHAR(10), f1, 120) AS ff1, 
     CONVERT(VARCHAR(10), f2, 103) AS ff2, 
     ..., 
     Bonus, 
     Malus, 
     ClientID, 
     SUM(Bonus) OVER (PARTITION BY ClientID) AS ClientBonusTotal, 
     SUM(Malus) OVER (PARTITION BY ClientID) AS ClientMalusTotal 
    FROM 
     my_table       
    WHERE 
     <my_conditions> 
) a 
WHERE ISNULL(a.ClientBonusTotal, 0) <> 0 OR ISNULL(a.ClientMalusTotal, 0) <> 0 
ORDER BY f1 ASC