PostgreSQL GROUP BY问题

时间:2012-03-08 14:01:57

标签: postgresql group-by distinct

假设我有表

      id      |       name       | number  |                address
--------------+------------------+---------+-------------------------------------
 1            | channel A        |      0  | http://stream01
 2            | channel B        |      2  | http://stream02
 3            | channel C        |      16 | http://stream03
 4            | channel B        |      2  | http://stream04
 5            | channel B        |      16 | http://stream05
 6            | channel C        |      16 | http://stream06
 7            | channel A        |      7  | http://stream07
 8            | channel A        |      5  | http://stream08
 9            | channel A        |      0  | http://stream09
...etc

我想删除重复的频道(具有相同名称和号码的行)。但我希望结果包含其他列以及名称和编号。

问题是我删除重复项后选择的idaddress。我很高兴选择它找到的第一个。因此,例如,上表的结果应为

      id      |       name       | number  |                address
--------------+------------------+---------+-------------------------------------
 1            | channel A        |      0  | http://stream01
 2            | channel B        |      2  | http://stream02
 3            | channel C        |      16 | http://stream03
 5            | channel B        |      16 | http://stream05
 7            | channel A        |      7  | http://stream07
 8            | channel A        |      5  | http://stream08
...etc

我意识到我的查询中可能需要SELECT name,number FROM table GROUP BY name,number,查询应该从SELECT id,name,number,address FROM (..)开始,但我想不出在一个查询中执行此操作的方法。

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

SELECT DISTINCT ON (name,number)
       id,
       name,
       number,
       address
  FROM table
 ORDER BY name,number,id;

答案 1 :(得分:0)

SELECT min(id),
       name,
       number,
       min(address)
FROM the_table
GROUP BY name, number;

修改
如果您需要匹配ID和地址,那么以下是另一种解决方案:

SELECT id, 
       name, 
       number, 
       address
FROM ( 
  SELECT id,
         name,
         number,
         address, 
         row_number() over (partition by name, number order by id) as rn
  FROM the_table
) t
WHERE rn = 1

答案 2 :(得分:0)

这应该足够了:

 SELECT MIN(id), name, number, address FROM table GROUP BY name, number

答案 3 :(得分:0)

我认为最容易理解的方法是使用视图或公用表表达式。我将使用公用表表达式。

create table test (
  id integer primary key,
  name varchar(20) not null,
  number integer not null,
  address varchar(30) not null
);

insert into test values 
(1, 'channel A', 0, 'http://stream01'),
(2, 'channel B', 2,   'http://stream02'),
(3, 'channel C', 16,  'http://stream03'),
(4, 'channel B', 2,   'http://stream04'),
(5, 'channel B', 16,  'http://stream05'),
(6, 'channel C', 16, 'http://stream06'),
(7, 'channel A', 7, 'http://stream07'),
(8, 'channel A', 5, 'http://stream08'),
(9, 'channel A', 0, 'http://stream09');

with unique_name_num as (
  select distinct name, number
  from test
),
min_id as (
  select number, name, min(id) id
  from test
  group by number, name
)
select t.*
from test t
inner join unique_name_num u on u.name = t.name and u.number = t.number
inner join min_id m on m.number = t.number and m.name = t.name and m.id = t.id
order by t.name, t.number