Добавление уникального ограничения на несколько столбцов с нарушением строк - PullRequest
1 голос
/ 03 апреля 2012

Мы пытаемся добавить уникальное ограничение в нашу таблицу postgres таким образом, чтобы удалить дубликаты, а не выдавать ошибку. Уникальное ограничение охватывает два столбца, а первичный ключ отсутствует. Например:

i_id | term   | date_created
1    | 'mako' | 123456789
1    | 'mako' | 123451234
1    | 'tele' | 213456852
2    | 'rake' | 598521542

Итак, в этом примере нам нужно будет удалить эту вторую строку, прежде чем мы сможем безопасно добавить ограничение уникальности. Обычно мы выполняем команду удаления с добавлением отдельного выделенного элемента, но у нас нет отличительного ключа для строк. В частности, уникальный ключ будет находиться над столбцами [i_id, term].

(WTF разве у нас не было уникального ограничения с самого начала? Иди с цифрой.)

Я думаю, что удаление лучше всего, но я не могу просто написать

delete from table where row_id not in (select row_id ... distinct something ... )

потому что нет первичного ключа для строки. Я бы предпочел избежать временной таблицы, если это возможно. Есть предложения?

РЕДАКТИРОВАТЬ: Извините. Мы используем postgres 8.4.

РЕДАКТИРОВАТЬ 2: Решение, которое мы используем:

delete from table where ctid not in (
  select 
    distinct on (i_id, term)
    ctid
    from table
    order by i_id, term
);

Спасибо, ребята!

Ответы [ 2 ]

2 голосов
/ 03 апреля 2012
DELETE FROM the_table
WHERE ctid NOT IN (SELECT min(b.ctid)
                   FROM the_table b
                   GROUP BY b.i_id, b.term)
0 голосов
/ 03 апреля 2012

Похоже, что у ваших дупсов есть различия в столбце date_created, так что вы можете использовать функцию windowing , чтобы получить значения всех, кроме первой строки для ваших дублированных наборов, а затем использовать ее для удаления толькодополнительные строки.

delete from foo
using 
(select i_id, term, date_created
 from (
  select foo.*
    , row_number() over (partition by i_id, term order by date_created asc) the_rank
  from foo
 ) ranked
 where ranked.the_rank <> 1
) extras
where foo.i_id = extras.i_id and foo.term = extras.term and foo.date_created = extras.date_created;

Это в значительной степени похоже на ответ Эрвина.Он отличается тем, что выбирает самую старую запись для сохранения вместо самой последней, которую можно изменить, изменив порядок на DESC из ASC в ранжированном подзапросе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...