PostgreSQL-使用不同时保留相对位置

时间:2018-08-18 18:47:44

标签: sql postgresql distinct

我运行了一个查询,该查询返回了一个这样的表。

 d |  e  | f  
---+-----+----
 2 | 103 | C
 6 | 201 | AB
 1 | 102 | B
 1 | 102 | B
 1 | 102 | B
 1 | 102 | B
 1 | 102 | B
 3 | 105 | E
 3 | 105 | E
 3 | 105 | E

我想要的是获取不同的行,但是要有序。基本上我想要这个:

2 | 103 | C
6 | 201 | AB
1 | 102 | B
3 | 105 | E

我尝试过distinctgroup by,但是他们并不总是保留职位(他们在我遇到的其他情况下保留了职位)。关于如何轻松完成此操作的任何想法,还是需要使用其他功能,例如rank

3 个答案:

答案 0 :(得分:1)

在以下情况下的用例:

order by case when f=C then 1 when f=AB then 2
when f=B then 3 when f=E then 5 else null end

答案 1 :(得分:1)

SQL表表示无序集。除非您具有带有列或表达式的显式order by,否则不进行排序。

如果您有这样的订购,则可以使用group by做您想做的事情:

select d, e, f
from t
group by d, e, f
order by min(a);  -- assuming a is the column that specifies the ordering

答案 2 :(得分:0)

您可以尝试在order by ctid列中描述行的物理位置,以识别行。

  

表中行版本的物理位置。请注意,尽管可以使用ctid快速定位行版本,但是如果通过VACUUM FULL更新或移动了行的ctid,则该行的ctid将会更改。因此,ctid不能用作长期行标识符。应该使用OID或更好的用户定义序列号来标识逻辑行。

使用row_number windows函数通过ctid生成行号。

然后得到rn = 1order by ctid

CREATE TABLE T(
  d int,
  e int,
  f varchar(5)
);

insert into t values (2,103, 'C');
insert into t values (6,201, 'AB');
insert into t values (1,102, 'B');
insert into t values (1,102, 'B');
insert into t values (1,102, 'B');
insert into t values (1,102, 'B');
insert into t values (1,102, 'B');
insert into t values (3,105, 'E');
insert into t values (3,105, 'E');
insert into t values (3,105, 'E');

查询1

select d,e,f 
from (
  select d,e,f,ctid,row_number() over(partition by d,e,f order by ctid) rn
  FROM T
)t1
where rn = 1
order by ctid

Results

| d |   e |  f |
|---|-----|----|
| 2 | 103 |  C |
| 6 | 201 | AB |
| 1 | 102 |  B |
| 3 | 105 |  E |