如何通过SQL选择唯一记录


87

当我执行“ SELECT * FROM table”时,得到的结果如下:

1 item1 data1
2 item1 data2
3 item2 data3
4 item3 data4

如您所见,存在column2中的dup记录(重复了item1)。所以我怎么能得到这样的结果:

1 item1 data1
2 item2 data3
3 item3 data4

从重复项中仅返回一条记录,以及其余的唯一记录。


项目1在技术上没有重复。如图所示,第1行和第2行是唯一的观察结果。如果您想保留第2行而不是第1行怎么办?
控制论

Answers:


105

使用distinct具有单个和多个列名称的关键字,您将获得不同的记录:

SELECT DISTINCT column 1, column 2, ...
FROM table_name;

14
答案可能是错误的吗?DISTINCT应用于所有选定的列(至少在DB2上),该列仍将在各个列中返回重复值。
康斯坦丁


11

这取决于要为每个唯一项目返回的行。您的数据似乎表明了最小数据值,因此在这种情况下对于SQL Server。

SELECT item, min(data)
FROM  table
GROUP BY item

10

您可以使用4种方法:

  1. 不同
  2. 通过...分组
  3. 子查询
  4. 带有ROW_NUMBER()的公用表表达式(CTE)

考虑以下TABLE带有测试数据的示例:

/** Create test table */
CREATE TEMPORARY TABLE dupes(word text, num int, id int);

/** Add test data with duplicates */
INSERT INTO dupes(word, num, id)
VALUES ('aaa', 100, 1)
      ,('bbb', 200, 2)
      ,('ccc', 300, 3)
      ,('bbb', 400, 4)
      ,('bbb', 200, 5)     -- duplicate
      ,('ccc', 300, 6)     -- duplicate
      ,('ddd', 400, 7)
      ,('bbb', 400, 8)     -- duplicate
      ,('aaa', 100, 9)     -- duplicate
      ,('ccc', 300, 10);   -- duplicate

选项1:SELECT DISTINCT

这是最简单直接的方法,也是最有限的方法:

SELECT DISTINCT word, num 
FROM    dupes
ORDER BY word, num;

/*
word|num|
----|---|
aaa |100|
bbb |200|
bbb |400|
ccc |300|
ddd |400|
*/

选项2:GROUP BY

分组允许您添加汇总数据,如min(id)max(id)count(*),等:

SELECT  word, num, min(id), max(id), count(*)
FROM    dupes
GROUP BY word, num
ORDER BY word, num;

/*
word|num|min|max|count|
----|---|---|---|-----|
aaa |100|  1|  9|    2|
bbb |200|  2|  5|    2|
bbb |400|  4|  8|    2|
ccc |300|  3| 10|    3|
ddd |400|  7|  7|    1|
*/

选项3:子查询

使用子查询,您可以首先标识要忽略的重复行,然后使用WHERE NOT IN (subquery)构造在外部查询中将其过滤掉:

/** Find the higher id values of duplicates, distinct only added for clarity */
    SELECT  distinct d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id

/*
id|
--|
 5|
 6|
 8|
 9|
10|
*/

/** Use the previous query in a subquery to exclude the dupliates with higher id values */
SELECT  *
FROM    dupes
WHERE   id NOT IN (
    SELECT  d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id
)
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

选项4:带有ROW_NUMBER()的公用表表达式

在公用表表达式(CTE)中,选择ROW_NUMBER(),按组列划分并以所需顺序排序。然后仅选择具有ROW_NUMBER() = 1以下内容的记录:

WITH CTE AS (
    SELECT  *
           ,row_number() OVER(PARTITION BY word, num ORDER BY id) AS row_num
    FROM    dupes
)
SELECT  word, num, id 
FROM    cte
WHERE   row_num = 1
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

6

只使用内部联接,因为group by不能与多个列中的任何一个聚合函数都不包含一起使用。

SELECT a.*
FROM yourtable a
INNER JOIN 
  (SELECT yourcolumn,
    MIN(id) as id
  FROM yourtable 
  GROUP BY yourcolumn
) AS b
  ON a.yourcolumn= b.yourcolumn
  AND a.id = b.id;

那是对另一个问题的答案,可能是应该用每组最大n
a_horse_with_no_name

这和Dave Baker的解决方案是SO问题的正确解决方案。该解决方案的优势在于,它允许选择仅包含一些指定的不同列的行,并且必须定义一个MIN(id)AS ID列才能仅选择多个指定列中的一个。
佐丹奴


1

要获得结果中的所有列,您需要放置以下内容:

SELECT distinct a, Table.* FROM Table

它将放置a作为第一列,其余的将是所有列,其顺序与您的定义相同。即,将重复列a


1
你确定吗?我在w3schools上尝试了此方法,它返回的内容与SELECT *相同,只不过第一列是
2015年

@怪异的是,那正是我的回答所
要说的

这将行不通,您不能在类似的
字符

@Mohsinkhan好吧,我忘了放置您需要写表名称的地方。不知何故,当我编写此代码时,它起作用了,但我现在进行了测试,并且在*之前没有表名
htafoya

2
这与select distinct * from ...
a_horse_with_no_name

-4

从(选择EFF_ST,ROW_NUMBER()超过(PARTITION BY eff_st)XYZ-从ABC中选择Eff_st.CODE_DIM

),其中XYZ = 1乘EFF_ST只能获取前5行

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.