SQL / mysql - 选择distinct / UNIQUE但返回所有列?

时间:2011-05-25 15:55:16

标签: sql select distinct

SELECT DISTINCT field1, field2, field3, ......   FROM table

我正在尝试完成以下sql语句,但我希望它返回所有列这可能吗?类似的东西:

SELECT DISTINCT field1, * from table

18 个答案:

答案 0 :(得分:371)

您正在寻找一个小组:

select *
from table
group by field1

偶尔可以使用明确的声明编写:

select distinct on field1 *
from table

但是,在大多数平台上,上述两种方法都不起作用,因为未指定其他列上的行为。 (第一个在MySQL中运行,如果你正在使用它。)

您可以获取不同的字段,并坚持每次都选择一个任意行。

在某些平台上(例如PostgreSQL,Oracle,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),所以不推荐。

答案 1 :(得分:53)

根据您的问题的措辞,我理解您要为给定字段选择不同的值,并为每个这样的值选择列出的同一行中的所有其他列值。大多数DBMS都不允许使用DISTINCTGROUP BY,因为结果未确定。

可以这样想:如果您的field1出现多次,则会列出field2的值(假设您在两行中的field1具有相同的值,但这两行中field2的两个不同值。)

然而,您可以使用聚合函数(对于您希望显示的每个字段都明确表示)并使用GROUP BY代替DISTINCT

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

答案 2 :(得分:20)

如果我正确地理解了你的问题,它就像我刚才那样。您希望能够将DISTINCT的可用性限制为指定字段,而不是将其应用于所有数据。

如果您使用没有聚合函数的GROUP BY,那么GROUP BY将成为您的DISTINCT字段。

如果您提出疑问:

SELECT * from table GROUP BY field1;

它将根据field1的单个实例显示所有结果。

例如,如果您有一个包含姓名,地址和城市的表格。一个人记录了多个地址,但您只需要一个人的地址,您可以按如下方式查询:

SELECT * FROM persons GROUP BY name;

结果将只显示该名称的一个实例及其地址,另一个将从结果表中省略。警告:如果您的文件具有原子值,例如firstName,则您希望将lastName分组。

SELECT * FROM persons GROUP BY lastName, firstName;

因为如果两个人姓氏相同而你只按lastName分组,那么结果中将省略其中一个人。你需要考虑这些事情。希望这可以帮助。

答案 3 :(得分:12)

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

答案 4 :(得分:7)

这是一个非常好的问题。我已经在这里阅读了一些有用的答案,但我可以添加一个更精确的解释。

只要您不查询其他信息,使用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中抛出一个错误,因为你的计算机怎么能知道你想在“法国”右边的字段中读到的三个法国城市“Lyon”,“Paris”或“Marseille”中的哪一个?

要更正第二个查询,您必须添加此信息。一种方法是使用函数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

将导致:

--country-- --city--
 France      Marseille
 Poland      NULL
 Italy       Milano

答案 5 :(得分: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

答案 6 :(得分: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子句查询中选择的行。

答案 7 :(得分:1)

尝试

SELECT table.* FROM table 
WHERE otherField = 'otherValue'
GROUP BY table.fieldWantedToBeDistinct
limit x

答案 8 :(得分: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的每个不同组合进行行计数。

答案 9 :(得分:0)

在这里的其他地方找到了这个,但这是一个可行的简单解决方案:

 WITH cte AS /* Declaring a new table named 'cte' to be a clone of your table */
 (SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY val1 DESC) AS rn
 FROM MyTable /* Selecting only unique values based on the "id" field */
 )
 SELECT * /* Here you can specify several columns to retrieve */
 FROM cte
 WHERE rn = 1

答案 10 :(得分:0)

select min(table.id), table.column1
from table 
group by table.column1

答案 11 :(得分:0)

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

ORDER BY我刚刚在这里举例,你也可以在这个

中添加ID字段

答案 12 :(得分:-1)

将GROUP BY添加到要检查重复项的字段 您的查询可能看起来像

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

将检查field1以排除重复记录

或者您可以查询

SELECT *  FROM table GROUP BY field1

从SELECT

中排除了field1的重复记录

答案 13 :(得分:-2)

可以通过内部查询

来完成
$query = "SELECT * 
            FROM (SELECT field
                FROM table
                ORDER BY id DESC) as rows               
            GROUP BY field";

答案 14 :(得分:-2)

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

答案 15 :(得分:-3)

如果表中所有三列的值都是唯一的,则SELECT DISTINCT FIELD1,FIELD2,FIELD3 FROM TABLE1有效。

例如,如果您的名字有多个相同的值,但所选列中的姓氏和其他信息不同,则该记录将包含在结果集中。

答案 16 :(得分:-3)

我建议使用

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

这样,如果跨越多行在field1中具有相同的值,则将返回所有记录。

答案 17 :(得分:-3)

SELECT * from table where field in (SELECT distinct field from table)