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

ary*_*axt 352 sql select distinct

SELECT DISTINCT field1, field2, field3, ......   FROM table
Run Code Online (Sandbox Code Playgroud)

我试图完成以下sql语句,但我希望它返回所有列是否可能?就像是:

SELECT DISTINCT field1, * from table
Run Code Online (Sandbox Code Playgroud)

Den*_*rdy 383

您正在寻找一个小组:

select *
from table
group by field1
Run Code Online (Sandbox Code Playgroud)

偶尔可以使用不同的语句编写:

select distinct on field1 *
from table
Run Code Online (Sandbox Code Playgroud)

但是,在大多数平台上,上述任何一个都不起作用,因为未指定其他列上的行为.(第一个在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
Run Code Online (Sandbox Code Playgroud)

在其他人(MySQL,SQLite)上,你需要编写子查询来使你自己加入整个表(例子),所以不推荐.

  • 查询不会为我解析并给出错误:`排名函数"row_number"必须有一个ORDER BY子句.我们需要在按field1分区后添加order by子句.所以正确的查询将是`select*from(select*,row_number()over(partition by order1 order by orderbyFieldName)as row_number from table)as row_number = 1 (10认同)
  • `选择不同的(field1)* from table`; 也适用于 PostgreSQL (5认同)
  • 同样在Oracle(Oracle SQL Developer)中,您不能在表的row_number上指定`select *,row_number()(按field1分区,按field2分区)。您必须在选择查询`select ** table **。*中,将row_number()替换为表的row_number来显式使用表名/别名。 (2认同)

Cos*_*atu 57

根据您的问题的措辞,我理解您要为给定字段选择不同的值,并为每个这样的值选择列出的同一行中的所有其他列值.大多数DBMS不会让这种既没有DISTINCT也没有GROUP BY,因为结果并不确定.

可以这样想:如果您field1不止一次出现,field2将列出什么值(假设您field1在两行中具有相同的值,但在这两行中有两个不同的值field2).

但是,您可以使用聚合函数(对于您希望显示的每个字段显式)并使用GROUP BY而不是DISTINCT:

SELECT field1, MAX(field2), COUNT(field3), SUM(field4), .... FROM table GROUP BY field1
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案为+1.所以我们可以做`SELECT field1,MIN(field2),MIN(field3),MIN(field4),.... FROM GROUP GROUP BY field1`,field2,3,4 ,,,不需要是整数(或其他数字),它们也可以是char字段 (4认同)

roc*_*zen 22

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

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

如果您提出以下问题:

SELECT * from table GROUP BY field1;
Run Code Online (Sandbox Code Playgroud)

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

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

SELECT * FROM persons GROUP BY name;
Run Code Online (Sandbox Code Playgroud)

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

SELECT * FROM persons GROUP BY lastName, firstName;
Run Code Online (Sandbox Code Playgroud)

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


Sto*_*rmy 13

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
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说看起来很有希望,但它仍然带回所有行,而不是不同的 field1。:( (3认同)
  • 我相信这是因为我使用了RedGate SQLPrompt.我配置它的方式,它总是添加别名 - 即使没有必要.它就是"以防万一" (2认同)

小智 8

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

只要不查询其他信息,使用GROUP BY语句减少查询结果的数量就很容易.我们假设你有下表"位置".

--country-- --city--
 France      Lyon
 Poland      Krakow
 France      Paris
 France      Marseille
 Italy       Milano
Run Code Online (Sandbox Code Playgroud)

现在查询

SELECT country FROM locations
GROUP BY country
Run Code Online (Sandbox Code Playgroud)

将导致:

--country--
 France
 Poland
 Italy
Run Code Online (Sandbox Code Playgroud)

但是,以下查询

SELECT country, city FROM locations
GROUP BY country
Run Code Online (Sandbox Code Playgroud)

...在MS SQL中抛出一个错误,因为你的计算机怎么能知道你想在"法国"右边的字段中读到的三个法国城市"Lyon","Paris"或"Marseille"中的哪一个?

要更正第二个查询,您必须添加此信息.一种方法是使用函数MAX()或MIN(),选择所有候选中的最大值或最小值.MAX()和MIN()不仅适用于数值,还可以比较字符串值的字母顺序.

SELECT country, MAX(city) FROM locations
GROUP BY country
Run Code Online (Sandbox Code Playgroud)

将导致:

--country-- --city--
 France      Paris
 Poland      Krakow
 Italy       Milano
Run Code Online (Sandbox Code Playgroud)

要么:

SELECT country, MIN(city) FROM locations
GROUP BY country
Run Code Online (Sandbox Code Playgroud)

将导致:

--country-- --city--
 France      Lyon
 Poland      Krakow
 Italy       Milano
Run Code Online (Sandbox Code Playgroud)

只要您可以从字母(或数字)顺序的两端选择值,这些函数就是一个很好的解决方案.但如果不是这样呢?让我们假设您需要具有特定特征的值,例如以字母"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
Run Code Online (Sandbox Code Playgroud)

将导致:

--country-- --city--
 France      Marseille
 Poland      NULL
 Italy       Milano
Run Code Online (Sandbox Code Playgroud)


Gar*_*son 5

好问题@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
Run Code Online (Sandbox Code Playgroud)


小智 5

尝试

SELECT table.* FROM table 
WHERE otherField = 'otherValue'
GROUP BY table.fieldWantedToBeDistinct
limit x
Run Code Online (Sandbox Code Playgroud)