2015-03-17 3 views
0

У меня есть простая таблица базы данныхудалить повторяющиеся строки, но сохранить предпочтительную строку

create table demo (
    id  integer PRIMARY KEY, 
    fv  integer, 
    sv  text, 
    rel_id integer, 
    FOREIGN KEY (rel_id) 
    REFERENCES demo(id)); 

и я хочу, чтобы удалить все повторяющиеся строки, сгруппированных по fv и sv. Это уже fairly popular question с отличными ответами. Но мне нужен поворот в этом сценарии. Как и в случаях, когда rel_id is NULL Я хочу сохранить эту строку. В любом другом случае все идет.

Таким образом, используя следующие значения

insert into demo (id,fv,sv,rel_id) 
VALUES (1,1,'somestring',NULL), 
     (2,2,'somemorestring',1), 
     (3,1,'anotherstring',NULL), 
     (4,2,'somemorestring',3), 
     (5,1,'somestring',3) 

Либо

id | fv |  sv   | rel_id 
---+----+------------------+------- 
1 | 1 | 'somestring'  | NULL 
2 | 2 | 'somemorestring' | 1 
3 | 1 | 'anotherstring' | NULL 

или

id | fv |  sv   | rel_id 
---+----+------------------+------- 
1 | 1 | 'somestring'  | NULL 
3 | 1 | 'anotherstring' | NULL 
4 | 2 | 'somemorestring' | 3 

бы действительные результаты. Где в качестве

id | fv |  sv   | rel_id 
---+----+------------------+------- 
3 | 1 | 'anotherstring' | NULL 
4 | 2 | 'somemorestring' | 3 
5 | 1 | 'somestring'  | 3 

не было. Поскольку первая запись имела NULL как rel_id, которая занимает пост президента выше NOT NULL.

В настоящее время у меня есть это (это ответ на основной дублированный вопрос) в качестве запроса на удаление дубликатов, но я не уверен, как продолжить изменять запрос в соответствии с моими потребностями.

DELETE FROM demo 
WHERE id NOT IN (SELECT min(id) as id 
        FROM demo 
        GROUP BY fv,sv) 

Как как только NOT NULL запись вставляется в базу данных до NULL въезда в не будут удалены NOT NULL один. Гарантируется, что rel_id всегда укажет на запись, где rel_id - NULL, поэтому нет опасности удаления ссылки. Далее гарантируется, что не будет двух строк в одной группе с rel_id IS NULL. Поэтому строка с rel_id IS NULL уникальна для всей таблицы.

Или в качестве основного алгоритма:

  1. Подойдите все строки и сгруппировать их по fv и sv
  2. Посмотрите в каждую группу для строки, где rel_id IS NULL. Если эта строка сохраняется (и удаляет остальные). Else выберите один ряд по вашему выбору и удалите остальные.

sqlfiddle

+0

Я вижу, что вы проделали серьезную работу по попытке решить, но я не могу четко решить задачу.Существуют ли условия для удаления записей с помощью 'rel_id = NULL'? Если нет, просто добавьте 'WHERE rel_id IS NOT NULL' во внутренний' select' –

+0

@KirillSlatin, который убьет любую строку, в которой есть 'NULL' запись в' rel_id'. Я буду редактировать в дальнейших объяснениях. – Sim

ответ

0

Я, кажется, работали его

DELETE FROM demo 
    WHERE id NOT IN (SELECT min(id) as id 
         FROM demo AS out_buff 
         WHERE rel_id IS NULL OR 
          NOT EXISTS (SELECT id FROM demo AS in_buff 
             WHERE rel_id IS NULL AND 
               in_buff.fv = out_buff.fv AND 
               in_buff.sv = out_buff.sv) 
         GROUP BY fv,sv); 

путем выбора во внутреннем SELECT либо только строки с rel_id со значением NULL или всех строк, соответствующих по GROUP BY аргументов , используя анти-условие к существованию строки с rel_id IS NULL. Но мой запрос выглядит действительно неэффективным. Поскольку наивное предположение поставило бы время работы не менее O(n^2).

+0

у вас есть 2 вложенных запроса. Это может иметь проблемы с производительностью для больших наборов данных. Если я правильно понял ваше объяснение, вам нужно [включить NULL в свою общую функцию MIN] (http://stackoverflow.com/questions/21286215/how-can-i-include-null-values-in-a-min- или-макс) –

Смежные вопросы