2011-05-25 137 views
273
SELECT DISTINCT field1, field2, field3, ...... FROM table 

我想完成下面的sql語句,但我希望它返回所有列是可能的嗎?喜歡的東西:SQL/mysql - 選擇distinct/UNIQUE,但返回所有列?

SELECT DISTINCT field1, * from table 
+8

爲什麼'SELECT DISTINCT * FROM table'不適合你? – 2011-05-25 15:57:13

+15

如果你的表有一個PK,根據定義,所有的行應該是'distinct'。如果你試圖選擇'DISTINCT field1',但不知何故返回所有其他列應該發生那些具有特定'field1'值的多個值的列?例如,您需要使用「GROUP BY」和其他列上的某種聚合。 – 2011-05-25 15:57:39

+1

如果您想要重複的行而不僅僅是不同的行,請刪除不同的關鍵字。 – Hyperboreus 2011-05-25 15:57:44

回答

303

你看一組:

select * 
from table 
group by field1 

哪些偶爾可以用不同的書面陳述上:

select distinct on field1 * 
from table 

在大多數平臺但是,以上都不會起作用,因爲其他列上的行爲未指定。 (如果你使用的是MySQL的第一個作品)。

你可以獲取不同的字段,並堅持每次選擇一個任意的行。

在某些平臺上(如PostgreSQL的,甲骨文,T-SQL)可以做到這一點直接利用窗口函數:

select * 
from (
    select *, 
      row_number() over (partition by field1 order by field2) as row_number 
    from table 
    ) as rows 
where row_number = 1 

在別人(MySQL和SQLite的),你需要編寫子查詢即會讓你加入整個表格(example),所以不推薦。

+0

我覺得你(由字段1分區)上忘了一個別名'ROW_NUMBER()row_number' – 2011-05-25 16:17:18

+0

我認爲這是自動設置(這是在Postgres的),但仍將編輯。 :-) – 2011-05-25 16:19:19

+10

該查詢不會解析我,並給出錯誤:'排名函數「row_number」必須有一個ORDER BY子句'。 我們需要在field1分區後添加order by子句。所以,正確的查詢將 '(超過(分區由FIELD1爲了通過orderbyFieldName)作爲ROW_NUMBER 從表 SELECT *, ROW_NUMBER())爲行 選擇* 其中ROW_NUMBER = 1' – 2012-11-27 06:23:44

10
SELECT c2.field1 , 
     field2 
FROM (SELECT DISTINCT 
       field1 
     FROM dbo.TABLE AS C 
     ) AS c1 
     JOIN dbo.TABLE AS c2 ON c1.field1 = c2.field1 
+0

爲什麼在沒有它的情況下可以使用'C''別名?在行'FROM dbo.TABLE AS C' – Talha 2017-10-02 10:53:21

42

從您的問題的措辭中,我瞭解到您要爲給定字段選擇不同的值,併爲每個此類值都列出同一行中的所有其他列值。大多數DBMS不會允許這與DISTINCTGROUP BY,因爲結果未確定。它

這樣想:如果出現你field1不止一次,將列出什麼field2值(假設你有field1兩行,但在這兩個行field2兩個不同的值相同的值)。

但是,您可以使用聚合函數(明確地定義爲要顯示的每個字段),並使用GROUP BY代替DISTINCT

SELECT field1, MAX(field2), COUNT(field3), SUM(field4), .... FROM table GROUP BY field1 
+2

+1這個解決方案。所以我們可以做'SELECT field1,MIN(field2),MIN(field3),MIN(field4),... FROM表GROUP BY field1',而field2,3,4 ,,,不需要是整數或其他數字),它們也可以是字符字段 – stalk 2015-07-21 13:51:22

+0

工作很好,直到我陷入布爾列。 MIN(動態)列值被修改爲假,即使它是真的。任何其他聚合函數可用於布爾 - signonsridhar 6分鐘前。總和(動態)將false更改爲1 – signonsridhar 2016-08-22 02:00:11

+0

偉大的建議,使我找到了我認爲更普遍的解決方案 - 請看一看! – 2016-12-16 22:04:37

-3
SELECT * from table where field in (SELECT distinct field from table) 
+7

這不會完成這項工作。您已經在子查詢中選擇了不同的列,但where子句獲取了具有該值的所有列。因此,查詢與編寫'select * from table'一樣好,除非'field'列是唯一的列,在這種情況下,該列上的不同部分根本不需要。 – 2012-11-27 06:08:42

2

您可以用WITH條款做到這一點。

例如:

WITH c AS (SELECT DISTINCT a, b, c FROM tableName) 
SELECT * FROM tableName r, c WHERE c.rowid=r.rowid AND c.a=r.a AND c.b=r.b AND c.c=r.c 

這也允許您選擇只在WITH子句查詢選擇的行。

15

如果我正確理解你的問題,它與我剛纔的問題類似。您希望能夠將DISTINCT的可用性限制到指定的字段,而不是將其應用於所有數據。

如果您使用沒有聚合函數的GROUP BY,那麼哪個字段GROUP BY將是您的DISTINCT字段。

如果你讓你的查詢:

SELECT * from table GROUP BY field1; 

它會顯示基於字段1的單個實例所有結果。

例如,如果您有一個名稱,地址和城市的表。單人都有記錄多個地址,但你只想要一個單一地址的人,你可以查詢如下:

SELECT * FROM persons GROUP BY name; 

結果是隻有一個名字的情況下會出現它的地址,另一個將從結果表中省略。警告:如果您的文件夾具有原子值,例如您想由兩者分組的firstName,lastName。

SELECT * FROM persons GROUP BY lastName, firstName; 

因爲如果兩個人擁有相同的姓氏,而您只按lastName分組,則其中一個人將從結果中省略。你需要考慮這些事情。希望這可以幫助。

+0

正如在接受的答案中提到的那樣,可以用於大多數SQL化身 - 僅適用於MYSQL – 2016-12-16 22:03:51

-2

只需將所有字段包含在GROUP BY子句中即可。

+1

也許提供您的意思的代碼示例? – doubleDown 2013-06-24 21:52:51

+2

爲了使這是一個很好的答案,你應該包含更多關於你的意思的細節。 – Robbert 2013-06-24 21:53:51

0
SELECT * 
FROM tblname 
GROUP BY duplicate_values 
ORDER BY ex.VISITED_ON DESC 
LIMIT 0 , 30 
ORDER BY

我剛纔把例子在這裏,你還可以添加ID字段在此

+0

正如在接受的答案中提到的那樣,可以用於大多數SQL化身 - 僅適用於MYSQL – 2016-12-16 22:01:07

-2

SELECT DISTINCT FIELD1,FIELD2,FIELD3 FROM TABLE1工作,如果所有三列的值在表中是唯一。

例如,如果您的名字有多個相同的值,但所選列中的姓氏和其他信息不同,則該記錄將包含在結果集中。

+0

這並不回答問題,OP正試圖獲取表的所有數據,但刪除包含單個字段的重複項的行 – 2016-12-16 22:00:07

-2

添加GROUP BY到現場要檢查重複 您的查詢可能看起來像

SELECT field1, field2, field3, ...... FROM table GROUP BY field1 

字段1將進行檢查,以排除重複的記錄

,或者您可以查詢像

SELECT * FROM table GROUP BY field1 

從選擇中排除field1的重複記錄

+1

GROUP BY子句必須匹配選定的字段。否則它會拋出錯誤,如'filed2必須出現在GROUP BY子句中或用於聚合函數中' – 2016-02-05 13:14:01

1

對於SQL Server,您可以使用dense_rank和其他窗口函數來獲取指定列上具有重複值的所有行和列。這裏是一個例子...

with t as (
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r1' union all 
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r2' union all 
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r3' union all 
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r4' union all 
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r5' union all 
    select col1 = 'a', col2 = 'a', col3 = 'a', other = 'r6' 
), tdr as (
    select 
     *, 
     total_dr_rows = count(*) over(partition by dr) 
    from (
     select 
      *, 
      dr = dense_rank() over(order by col1, col2, col3), 
      dr_rn = row_number() over(partition by col1, col2, col3 order by other) 
     from 
      t 
    ) x 
) 

select * from tdr where total_dr_rows > 1 

這是對col1,col2和col3的每個不同組合的行數。

+0

太複雜且特定於SQL的一個實現 – 2016-12-16 22:01:47

-1

它可以通過內部查詢來完成

$query = "SELECT * 
      FROM (SELECT field 
       FROM table 
       ORDER BY id DESC) as rows    
      GROUP BY field"; 
+0

這並不回答問題,OP正試圖獲取所有數據但刪除包含單個字段的重複項的行 – 2016-12-16 21:59:38

3

大問題@aryaxt - 你可以告訴它是一個很大的問題,因爲你5年前問它,我今天在其絆倒試圖找到答案!

我只是試圖編輯接受的答案,包括這一點,但如果我的編輯不會使它在:

如果你的表是沒有那麼大,並假設你的主鍵是自動遞增的整數你可以這樣做:

SELECT 
    table.* 
FROM table 
--be able to take out dupes later 
LEFT JOIN (
    SELECT field, MAX(id) as id 
    FROM table 
    GROUP BY field 
) as noDupes on noDupes.id = table.id 
WHERE 
    //this will result in only the last instance being seen 
    noDupes.id is not NULL 
+0

WHERE noDupes不爲NULL - 沒有爲表noDupes指定列,是嗎? – 2017-11-09 14:39:01

+0

@IstiaqueAhmed,很好的捕獲,只是編輯 – 2017-11-13 16:53:33

1

這是一個非常好的問題。我已經閱讀了一些有用的答案,但可能我可以添加更精確的解釋。

只要不查詢其他信息,使用GROUP BY語句減少查詢結果的數量就很容易。假設您獲得了下表中的「位置」。

--country-- --city-- 
France  Lyon 
Poland  Krakow 
France  Paris 
France  Marseille 
Italy  Milano 

現在查詢

SELECT country FROM locations 
GROUP BY country 

將導致:

--country-- 
France 
Poland 
Italy 

但是,下面的查詢

SELECT country, city FROM locations 
GROUP BY country 

...拋出一個錯誤在MS SQL,因爲你的電腦怎麼能知道這三個F中的哪一個你想在「法國」右邊的田野裏閱讀「里昂」,「巴黎」還是「馬賽」的城市?

爲了更正第二個查詢,您必須添加此信息。一種方法是使用函數MAX()或MIN(),在所有候選項中選擇最大或最小值。 MAX()和MIN()不僅適用於數值,還可以比較字符串值的字母順序。

SELECT country, MAX(city) FROM locations 
GROUP BY country 

將導致:

--country-- --city-- 
France  Paris 
Poland  Krakow 
Italy  Milano 

或:

SELECT country, MIN(city) FROM locations 
GROUP BY country 

將導致:

--country-- --city-- 
France  Lyon 
Poland  Krakow 
Italy  Milano 

這些功能是一個很好的解決方案,只要你是精從兩端選擇你的價值的字母(或數字)順序。但如果情況並非如此呢?讓我們假設你需要一個具有某種特徵的值,例如從字母'M'開始。現在事情變得複雜了。

我能找到到目前爲止,唯一的解決辦法是把你的整個查詢到一個子查詢,並通過手來構建它之外的附加列:

SELECT 
    countrylist.*, 
    (SELECT TOP 1 city 
    FROM locations 
    WHERE 
      country = countrylist.country 
      AND city like 'M%' 
    ) 
FROM 
(SELECT country FROM locations 
GROUP BY country) countrylist 

將導致:

​​
0

我會建議使用

SELECT * from table where field1 in 
(
    select distinct field1 from table 
) 

這樣,如果你有FIELD1 ACRO相同的值ss多行,所有記錄將被返回。