2011-05-25 140 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多行,所有记录将被返回。