2012-01-01 70 views
1

我必须从没有主键或唯一约束的表中清除记录。从没有唯一列的表中删除部分重复项

表定义:

create table person(
    name text, 
    staff_id integer, 
    work_code text, 
    location 
); 

不出所料,它含有大量的重复和部分重复的。 将记录转换为唯一集合的最佳方式是什么?我不必关心除名称和职员以外的其他专栏

+0

你称之为“部分重复”? – fge 2012-01-01 19:17:29

+0

@ work_code和location_fge变体,我只需要保留name和staff_id – 2012-01-01 19:18:47

+0

你真的关心哪些值会得到最终结果吗? – fge 2012-01-01 19:19:34

回答

4

正如你

不必在意除了名字等栏目和staff_id

这可能是你的程序来清理表:

1 )创建一个临时表独特行:

CREATE TEMP TABLE p_tmp AS 
SELECT DISTINCT ON (name, staff_id) 
     name, staff_id, work_code, location 
FROM person 
ORDER BY name, staff_id, work_code, location; 

我随意选择“第一行每(name, staff_id) - 最小work_code和匹配location

2)空表:

TRUNCATE person; 

3)重新插入独特的元组:

INSERT INTO person SELECT * FROM p_tmp; 

确保,受骗者不悄悄潜回里添加一个代理主键:

ALTER TABLE person ADD COLUMN person_id serial PRIMARY KEY; 
ALTER TABLE person ADD UNIQUE (name, staff_id); 

或者只需添加一个多列主键:

ALTER TABLE person ADD PRIMARY KEY (name, staff_id); 

临时表将在会话结束时自动丢弃。

当然,所有这一切最好在一个transaction内完成,所以在不太可能出现半途遇到问题的情况下不会丢失任何东西。有些客户端会自动执行一次执行的一批SQL语句。

+0

当然'max'比'min'更好;使空值最不可能被选中。 – Ben 2012-01-01 20:55:04

+0

@Ben:max()和min()都不会在**任何**值上选择NULL。 – 2012-01-01 21:05:20

+0

@ErwinBrandstetter谢谢你,它很好地工作 – 2012-01-02 04:47:19

0

也许这样?

select t.name, t.staff_id, t.work_code, t.location 
from (
    select name, staff_id, work_code, location, count(*) nr 
    from person 
    group by name, staff_id, work_code, location 
) t 
where t.nr > 1; 
+0

我很抱歉,我的意思是我需要摆脱部分重复行,但保留与所有其他值的1唯一行以及。我尝试不同,但它仍然返回所有行 – 2012-01-01 19:27:27

+0

请参阅后编辑,做它回答您的需求? – fge 2012-01-01 19:33:45

+0

它抱怨说我需要将所有t。*列包含在group by子句中。当我这样做时,它不返回任何行。我测试了子查询,并且“nr”列从不包含大于1的值。 – 2012-01-01 19:53:10