2011-01-11 113 views
54

的每個唯一值,讓我們說,我有客戶地址表:如何,只選擇第一行的列

CName   | AddressLine 
------------------------------- 
John Smith  | 123 Nowheresville 
Jane Doe  | 456 Evergreen Terrace 
John Smith  | 999 Somewhereelse 
Joe Bloggs  | 1 Second Ave 

在該表中,一個客戶像約翰·史密斯可以有多個地址。 我需要這個表的select查詢來返回只有第一行找到'CName'中有重複的地方。對於這個表,它應該返回除第三個(或第一個 - 這兩個地址中的任何一個都可以,但只有一個可以返回)以外的所有行。 是否有一個關鍵字可以添加到SELECT查詢中,以根據服務器是否已經看過列值進行過濾?

回答

82

一個非常簡單的答案,如果你說你不關心使用哪個地址。

SELECT 
    CName, MIN(AddressLine) 
FROM 
    MyTable 
GROUP BY 
    CName 

如果你想根據,比方說,一個 「插入」 欄,然後這是一個不同的查詢

SELECT 
    M.CName, M.AddressLine, 
FROM 
    (
    SELECT 
     CName, MIN(Inserted) AS First 
    FROM 
     MyTable 
    GROUP BY 
     CName 
    ) foo 
    JOIN 
    MyTable M ON foo.CName = M.CName AND foo.First = M.Inserted 
+3

對GROUP BY使用MIN似乎有效。 – nuit9 2011-01-11 21:28:46

+0

儘管在選擇10列時可能不會使用這種方式。也似乎它不能接受位類型的列。 – nuit9 2011-01-11 21:43:57

+0

@ nuit9:當然,它不會和位和10列一起工作。這些事實都不是你的問題。你會使用第二種技術或Ben Thul的技術。我回答了你特別提出的問題,並指出瞭如何更一般地解決問題。 – gbn 2011-01-12 04:53:54

19

在SQL 2K5 +,你可以這樣做第一:

;with cte as (
    select CName, AddressLine, 
    rank() over (partition by CName order by AddressLine) as [r] 
    from MyTable 
) 
select CName, AddressLine 
from cte 
where [r] = 1 
9

您可以使用row_number()來獲取行的行號。它使用over命令 - partition by子句指定何時重新開始編號,並且order by選擇要對行號進行排序的內容。即使您在查詢結尾添加了order by,編號時也會保留over命令中的排序。

select * 
from mytable 
where row_number() over(partition by Name order by AddressLine) = 1 
0

可以使用row_numer() over(partition by ...)語法像這樣:

select * from 
(
select * 
, ROW_NUMBER() OVER(PARTITION BY CName ORDER BY AddressLine) AS row 
from myTable 
) as a 
where row = 1 

這裏做的事情是,它創建了一個名爲row列,這是遞增每次看到同CName時間的計數器,以及通過AddressLine索引這些事件。通過施加where row = 1,人們可以選擇,其按字母順序排列。如果order bydesc,那麼它將選擇,其按字母順序排列。