2015-01-23 2 views
0

Я хочу удалить повторяющиеся строки из таблицы measurement в базе данных PostgreSQL 9.1.Удалить повторяющиеся строки ОШИБКА: дублировать значение ключа

Некоторые данные таблицы:

select column_name, data_type from information_schema.columns where table_name = 'measurement'; 

column_name | data_type 
-------------+----------- 
s_sum  | real 
s_l3  | real 
s_l2  | real 
s_l1  | real 
q_sum  | real 
q_l3  | real 
q_l2  | real 
q_l1  | real 
p_sum  | real 
p_l3  | real 
p_l2  | real 
p_l1  | real 
irms_n  | real 
irms_l3  | real 
irms_l2  | real 
irms_l1  | real 
urms_l3  | real 
urms_l2  | real 
urms_l1  | real 
timestamp | integer 
site  | integer 
id   | integer 
(22 rows) 

и

select count(*) from measurement; 

    count 
---------- 
56265678 
(1 row) 

Так что я хочу сделать, это удалить повторяющиеся строки, где все столбцы, кроме id равны. Я пошел вперед и попробовал это с подходом в this answer.

SET temp_buffers = '1GB'; 

BEGIN; 

CREATE TEMPORARY TABLE t_tmp AS 
SELECT DISTINCT site, 
      timestamp, 
      urms_l1, 
      urms_l2, 
      urms_l3, 
      irms_l1, 
      irms_l2, 
      irms_l3, 
      irms_n, 
      p_l1, 
      p_l2, 
      p_l3, 
      p_sum, 
      q_l1, 
      q_l2, 
      q_l3, 
      q_sum, 
      s_l1, 
      s_l2, 
      s_l3, 
      s_sum 
FROM measurement; 

TRUNCATE measurement; 

INSERT INTO measurement 
SELECT * FROM t_tmp; 

COMMIT; 

где эхо/ошибка:

SET 
BEGIN 
SELECT 56103537 
TRUNCATE TABLE 
ERROR: duplicate key value violates unique constraint "measurement_pkey" 
DETAIL: Key (id)=(1) already exists. 
ROLLBACK 

так это выглядит, как будто это было бы удалить дубликаты в порядке (сравните с количеством строк исходной таблицы measurement выше), но тогда основным ограничением ключа нарушается. Я действительно не знаю, что происходит здесь, я полагаю, что INSERT не работает на укороченной столе ...

Update:

Запрашиваемый SQL схема выглядит следующим образом:

-- 
-- PostgreSQL database dump 
-- 

SET statement_timeout = 0; 
SET client_encoding = 'UTF8'; 
SET standard_conforming_strings = on; 
SET check_function_bodies = false; 
SET client_min_messages = warning; 

-- 
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: - 
-- 

CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; 


-- 
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: - 
-- 

COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; 


SET search_path = public, pg_catalog; 

SET default_tablespace = ''; 

SET default_with_oids = false; 

-- 
-- Name: measurement; Type: TABLE; Schema: public; Owner: -; Tablespace: 
-- 

CREATE TABLE measurement (
    id integer NOT NULL, 
    site integer, 
    "timestamp" integer, 
    urms_l1 real, 
    urms_l2 real, 
    urms_l3 real, 
    irms_l1 real, 
    irms_l2 real, 
    irms_l3 real, 
    irms_n real, 
    p_l1 real, 
    p_l2 real, 
    p_l3 real, 
    p_sum real, 
    q_l1 real, 
    q_l2 real, 
    q_l3 real, 
    q_sum real, 
    s_l1 real, 
    s_l2 real, 
    s_l3 real, 
    s_sum real 
); 


-- 
-- Name: measurement_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
-- 

ALTER TABLE ONLY measurement 
    ADD CONSTRAINT measurement_pkey PRIMARY KEY (id); 


-- 
-- Name: public; Type: ACL; Schema: -; Owner: - 
-- 

REVOKE ALL ON SCHEMA public FROM PUBLIC; 
REVOKE ALL ON SCHEMA public FROM postgres; 
GRANT ALL ON SCHEMA public TO postgres; 
GRANT ALL ON SCHEMA public TO PUBLIC; 


-- 
-- PostgreSQL database dump complete 
-- 

А потом

SELECT id 
FROM measurement 
GROUP BY id 
HAVING COUNT(*) > 1; 

дает

id 
---- 
(0 rows) 
+0

Поскольку вы не указываете столбцы для предложения 'insert', вы помещаете значение столбца' site' из таблицы tmp в таблицу измерений. Если вы укажете столбцы в инструкции 'insert':' insert into measurement (site, ....) select ... from t_tmp', вы получите другую ошибку, потому что вы не укажете значение для ' id', и он также не имеет значения по умолчанию. Это очень хороший пример, почему вы никогда не должны использовать 'insert' без указания столбцов и почему вы никогда не должны использовать' select * '- ваши столбцы просто не соответствуют –

+0

@a_horse_with_no_name: Спасибо, что указали это. Он работал с использованием 'SELECT DISTINCT ON () FROM measurement'. FWIW, если вы ответите правильно, я приму это. – phaebz

ответ

1

Первичный ключ является уникальным ограничение на подмножество полей в measurement таблице, в то время как ваши SELECT DISTINCT возвращает только уникальные записи из полей, список, но выглядит на каждом поле в каждой записи, а не только первичный ключ

То есть у вас есть записи, которые имеют тот же первичный ключ (id, по-видимому), но имеют разные значения в неключевых полях.

Вы можете найти ключи, которые имеют повторяющиеся идентификаторы, выполнив:

SELECT id 
FROM t_tmp 
GROUP BY id 
HAVING COUNT(*) > 1; 

И вы можете просмотреть записи, относящиеся к тому, что, делая это:

SELECT * 
FROM t_tmp 
WHERE id IN (
    SELECT id 
    FROM t_tmp 
    GROUP BY id 
    HAVING COUNT(*) > 1 
); 

[Обратите внимание, что я указываю t_tmp выше , но если вы еще не запустили TRUNCATE TABLE measurement;, вместо этого вы можете использовать measurement.]

Это r ecords, которые дублируют идентификаторы, которые вызывают нарушения вашего ключа, при условии, что ключ находится только на id, что похоже на сообщение об ошибке. Вам нужно будет решить, какой из них сохранить, а какой - удалить, или иначе рассмотреть вопрос об обновлении поля id до нового уникального значения.

Непонятно, если id привязан к последовательности или был создан как SERIAL или BIGSERIAL в вашей новой таблице.Вы должны просто создать сценарий CREATE TABLE из pgAdmin, чтобы предоставить нам полную схему. Также неясно, есть ли другие уникальные ограничения для таблицы.

+0

Я обновил свой вопрос с недостающей информацией, которую вы запросили. – phaebz