Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Firebird, Interbase > Удаление дубликатов


Автор: Akella 15.12.2006, 10:40
В базе есть 2 связанные таблицы.

user posted image

Проблема в том, что хочу составить запрос, который удалит дубликаты из левой таблицы.
Нужно удалить все названия "Аверс", оставить только одну любую запись, не важно какую. Все телефоны из правой таблицы, которые на всех удаляемых  "Аверс`ах" перенести на ту, запись, которую оставляем.

Таких повторений много, поэтому нужно это сделать в цикле, в хранимке.

Левая таблица
Код

CREATE TABLE MEDIATORS (
    ID           "INT" NOT NULL /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */,
    NAME         STRING50 /* STRING50 = VARCHAR(50) */,
    EXP          BOOL COLLATE PXW_CYRL /* BOOL = VARCHAR(1) DEFAULT 'T' */,
    DELETED      BOOL COLLATE PXW_CYRL /* BOOL = VARCHAR(1) DEFAULT 'T' */,
    PHONES_LIST  COMPUTED BY ((select TELS_LIST from SP_TELS_LIST_MEDIATORS(MEDIATORS.ID))),
    UID          "INT" /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */,
    ID_TYPE      "INT" /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */
);


Правая таблица
Код

CREATE TABLE PHONES (
    ID           "INT" NOT NULL /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */,
    TEL          STRING20 NOT NULL COLLATE PXW_CYRL /* STRING20 = VARCHAR(20) */,
    ID_APART     "INT" /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */,
    ID_ARENDA    "INT" /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */,
    ID_OFF       "INT" /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */,
    ID_MEDIATOR  "INT" /* "INT" = INTEGER CHECK ((VALUE >= 0) or (VALUE is NULL) or (VALUE = -1)) */,
    EXP          BOOL COLLATE PXW_CYRL /* BOOL = VARCHAR(1) DEFAULT 'T' */
);


Таблицы связаны по ключу. Как видно из скриптов, по полям PHONES.ID_MEDIATOR и MEDIATORS.ID

Автор: Romkin 15.12.2006, 11:12
1. for select Посредники, min(ID) 
2. в цикле update для телефонов set ID = <minID> где их ID in (select ID from Посредники where Посредник = <переменная>)
3. все, осталось удалить дублирующихся посредников. Примеры запросов есть на ibase.ru
Так достаточно? smile

Автор: Akella 15.12.2006, 12:11
наверное

Добавлено @ 12:22 
вроде оно
Код

begin
 for select Min(m.ID) from MEDIATORS m
 group by m.name
 into :NEW_VAR
 do begin
   update PHONES p
   set p.ID_MEDIATOR = :NEW_VAR where p.ID_MEDIATOR in (select m.ID from MEDIATORS M where m.ID = :NEW_VAR);

 end
end

Автор: Akella 15.12.2006, 12:57
не, Romkin, ты не прав

хотябы вот этим

Цитата(Romkin @  15.12.2006,  11:12 Найти цитируемый пост)
for select Посредники, min(ID) 


Автор: Romkin 15.12.2006, 13:27
Почему? Это ты неизвестно чего делаешь своим запросом smile 
Поле обновляешь тем же значением  smile 
Код

update PHONES p    
   set p.ID_MEDIATOR = :NEW_VAR where p.ID_MEDIATOR in (select m.ID from MEDIATORS M where m.ID = :NEW_VAR);

Подзапрос возвращает четко только значения NEW_VAR smile 

Вот так примерно должно быть:
Код

begin    
 for select m.name, Min(m.ID) from MEDIATORS m    
 group by m.name    
 into :NAME, :NEW_VAR    
 do begin    
  --Переделываем ID на одно имя с наименьшим ID
   update PHONES p    
   set p.ID_MEDIATOR = :NEW_VAR where p.ID_MEDIATOR in (select m.ID from MEDIATORS M where m.name = :NAME);
  --удаляем все одинаковые имена с другими ID
  delete from MEDIATORS
  where name = :NAME and ID <> :NEW_VAR;    
 end    
end

Советую индексировать m.name - будет быстрее

Автор: Akella 15.12.2006, 14:52
    спасибо, с меня +

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)