MySQL中常用去重復數據的方法是使用 distinct 或者 group by ,以上2種均能實現,但2者也有不同的地方。
distinct 特點:
如:select distinct name, sex from tb_students 這個sql的語法中,查詢 tb_students 表中 name, sex 並去除名字和性別都重復的學生:
1、distinct 只能放在查詢字段的最前面,不能放在查詢字段的中間或者后面。
備注:select sex, distinct name from tb_students 這種寫法是錯誤的,distinct 只能寫在所有查詢字段的前面
2、distinct 對后面所有的字段均起作用,即 去重是查詢的所有字段完全重復的數據,而不是只對 distinct 后面連接的單個字段重復的數據。
備注:也就是 distinct 關鍵字對 name, sex 都起作用,去重姓名、性別完全一樣的學生,如果姓名相同、性別不同是不會去重的。
3、要查詢多個字段,但只針對一個字段去重,使用 distinct 去重的話是無法實現的。
group by 特點:
1、一般與聚類函數使用(如count()/sum()等),也可單獨使用。
2、group by 也對后面所有的字段均起作用,即 去重是查詢的所有字段完全重復的數據,而不是只對 group by 后面連接的單個字段重復的數據。
3、查詢的字段與 group by 后面分組的字段沒有限制。
特別說明:在 Oracle 中使用 group by 時,查詢的字段必須是 group by 分組的字段和聚類函數。如 select name, sex from tb_students group by name 這個 sql 語法在 Oracle 中是錯誤的,因為 sex 不在 group by 分組后面,但在 MySQL 中是支持的。
distinct 與 group by 的一些示例
在數據表中記錄了用戶驗證時使用的書目,現在想取出所有書目,用 distinct 和 group by 都取到了我想要的結果,但返回結果排列不同,distinct 會按數據存放順序一條條顯示,而 group by 會做個排序(一般是asc)。
distinct 實際上和 group by 操作的實現非常相似,只不過是在 group by 之后的每組中只取出一條記錄而已。所以,distinct 的實現和 group by 的實現也基本差不多,沒有太大的區別,同樣可以通過松散索引掃描或者是緊湊索引掃描來實現。
那 distinct 和 group by 哪個效率更高?
distinct 操作只需要找出所有不同的值就可以了。而 group by 操作還要為其他聚集函數進行准備工作。從這一點上將,group by 操作做的工作應該比 distinct 所做的工作要多一些。
但實際上,group by 效率會更高點,為什么呢?對於distinct操作,它會讀取了所有記錄,而 group by 需要讀取的記錄數量與分組的組數量一樣多,也就是說比實際存在的記錄數目要少很多。
下面來看 MySQL 中 distinct 及 group by 的一些用法分享。
1
2
3
4
|
CREATE
TABLE
`student` (
`
name
`
varchar
(20)
NOT
NULL
DEFAULT
''
,
`age`
int
(10)
DEFAULT
'0'
) ENGINE=InnoDB
DEFAULT
CHARSET=latin1
|
1. 測試一
1
|
select
*
from
student;
|
返回
1
2
3
|
a 5
a 5
c 0
|
用 distinct 過濾掉兩列都相同的記錄
1
|
select
distinct
name
,age
from
student;
|
返回
1
2
|
a 5
c 0
|
2. 測試二
將表 student 的數據改為如下:
1
|
select
*
from
student;
|
1
2
|
c 2
c 5
|
1
|
select
distinct
name
,age
from
student;
|
返回如下,說明 distinct 后面有多於一列的字段時,只有所有查詢列的值完全相同才過濾
1
2
|
c 2
c 5
|
3. 測試三
1
|
select
*
from
student;
|
返回
1
2
3
4
|
name
age height
c 2 123
c 2 456
b 20 222
|
group by 按兩列同時分組
1
|
select
name
,age,
sum
(height)
from
student
group
by
name
,age;
|
返回
1
2
|
b 20 222
c 2 579
|
group by 按兩列同時分組,同時在后面加上 having 的條件
1
|
select
name
,age,
sum
(height)
as
n
from
student
group
by
name
,age
having
n > 500;
|
返回
1
|
c 2 579
|
4. 測試四
關於 group by 后面 limit 的測試
1
|
select
songname,sengerid,
count
(sengerid)
as
n
from
t_song
group
by
songname,sengerid
having
n > 1
ORDER
BY
n
DESC
,songid
ASC
limit 10;
|
返回
1
2
3
4
5
6
7
8
9
10
|
未知 8738 40
共同渡過 1432 24
風繼續吹 1432 23
倩女幽魂 1432 23
無心睡眠 1432 23
羅百吉超嗨派對連續組曲 780 19
拒絕再玩 1432 19
風再起時 1432 18
每天愛你多一些 1480 18
千言萬語 1794 18
|
1
|
select
songname,sengerid,
count
(sengerid)
as
n
from
t_song
group
by
songname,sengerid
having
n > 1
ORDER
BY
n
DESC
,songid
ASC
limit 5;
|
返回
1
2
3
4
5
|
未知 8738 40
共同渡過 1432 24
風繼續吹 1432 23
倩女幽魂 1432 23
無心睡眠 1432 23
|
經過以上兩個測試可以看出,如果 sql 語句中含有 limit,limit 是對用 group by 進行分組,並進行相關計算以后的 limit 操作,而不是對 limit 后面的指定記錄數進行分組,從 n 那一列的數據每一行的值都大於 10就可以看出來。
5. 測試五
用以下的兩種形式的 distinct 均可以得到相同的記錄數,寫法不一樣,結果是一樣的。
1
2
|
select
count
(
distinct
(songid))
from
feedback;
select
count
(
distinct
songid)
from
feedback;
|
6. 測試六
field singername is string, max(singername),如果 singername 有些列為空,有些列不為空,則 max(singername) 取非空的值,如果一列值為'zxx', 一列值為'lady',則取'zxx',按字母順利取的。
1
|
select
feedback_id,songid,songname,
max
(singername),
max
(
time
)
as
new_time
from
feedback
group
by
songid
order
by
new_time
desc
;
|
7. Sql 語句中 where, group by, order by 及 limit 的順序
1
|
where
xxx,
group
by
xxx,
order
by
xxx,limit xxx
|
8. 關於 group by 與 count 的問題
如果 sql 語句中含有 group by,則最好不要將 count sql 轉換為 select count(*) from xxx,否則 select 與 from 之間的字段很有可能是后面要使用的,例如:
1
|
select
feedback_id,songid,songname,
max
(singername),
max
(
time
)
as
new_time
from
feedback
group
by
songid
order
by
new_time
desc
;
|
返回
1
|
MySQL Query Error:
SELECT
COUNT
(*)
FROM
feedback
group
by
songid
ORDER
BY
new_time
DESC
Error Info:Unknown
column
'new_time'
in
'order clause'
|
參考: