2011-09-17 31 views
1

我正在使用SSMS 2008,試圖只選擇一行/客戶端。我需要選擇以下列:client_name,end_dateprogram。有些客戶端只有一個客戶端行。但其他人有多個。如何開發t-sql子查詢,每個只選擇一條記錄?

對於那些有多行的客戶,他們通常有不同的end_dateprogram。例如:

CLIENT  PROGRAM  END_DATE 
a   b    c 
a   d    e 
a   f    g 
h   d    e 
h   f    NULL 

這是一個真正的簡化版本的實際數據。正如您將看到的,不同的客戶端可以在同一個程序中(「d」)。但同一個客戶不能在同一個程序中多次。

另外棘手的是end_date可以是NULL,所以當我嘗試選擇具有> 1行的客戶端時,我添加了HAVING語句> 1.但是這消除了我的所有NULL End_date行。總結一下,我想每個客戶端都有一行。因此,那些只有一行總數的客戶+上面列出的客戶使用以下標準:

  • 只選擇End_date最大或NULL的行。 (在大多數情況下,這些客戶端的end_date爲空)。

我該如何用盡可能少的邏輯來實現?

+0

我假設其中end_date爲NULL的行優先於max(end_date)。但是,如果客戶端對於兩個不同的程序具有NULL end_date,應該返回什麼,因爲您只希望每個客戶端返回一行? – user937146

回答

4

在SQL Server 2005及更高版本上,可以使用與ROW_NUMBER()PARTITION BY函數結合使用的通用表達式(CTE)。此CTE將按照一個標準「劃分」您的數據 - 您的情況爲Client,爲每個單獨的客戶端創建一個「分區」。然後,ROW_NUMBER()將按每個分區的順序對每個分區進行編號 - 在這裏我創建了一個DATETIME - 並分別爲每個分區從1開始分配數字。

所以在這種情況下,按DATETIME DESC排序,最新的一行編號爲1 - 這就是我從CTE中選擇時使用的事實。我在這裏使用ISNULL()函數來分配那些具有NULL值的行,以便「按順序獲取它們」。我不太清楚,如果我正確理解您的問題:您是否想要選擇那些具有給定的end_Date的NULL行,還是希望優先考慮NULL的現有end_Date值?

這將選擇最近爲每個客戶端的行(每個數據的「分區」):

DECLARE @clients TABLE (Client CHAR(1), Program CHAR(1), END_DATE DATETIME) 

INSERT INTO @clients 
VALUES('a', 'b', '20090505'), 
('a', 'd', '20100808'), 
('a', 'f', '20110303'), 
('h', 'd', '20090909'), 
('h', 'f', NULL) 

;WITH LatestData AS 
(
    SELECT Client, Program, End_Date, 
     ROW_NUMBER() OVER(PARTITION BY CLient ORDER BY ISNULL(End_Date, '99991231') DESC) AS 'RowNum' 
    FROM @clients 
) 
SELECT Client, Program, End_Date 
FROM LatestData 
WHERE RowNum = 1 

結果的輸出:

Client Program End_Date 
    a  f  2011-03-03 
    h  f  (NULL) 
+0

感謝Marc,我想選擇具有給定結束日期的NULL行。 – salvationishere

+0

@salvantionsishere:OK,在這種情況下,只需用99991231' - 9999年12月31日的ISNULL調用中的日期替換 - 那麼帶NULL的行將首先出現。 –

+0

超級!謝謝Marc;這正是我需要的! – salvationishere