Почему max (rowid) или min (rowid) присутствует при удалении повторяющихся записей?

0

Можно ли удалить дубликаты записей без использования Псевдо coloumn rowid... что значение макс (RowId)/мин (ROWID) в то время как удаление duplicte записи?

  • 1
    MySQL или оракул? какой вы используете? Да, есть несколько других методов, на которые здесь даны ответы: stackoverflow.com/questions/18390574/… и stackoverflow.com/questions/529098/… . но метод ROWID является наиболее эффективным.
  • 0
    Если таблица имеет уникальную комбинацию столбцов, то да, вы можете использовать их для определения удаляемых строк. Если вся строка дублируется, то вам нужен способ удалить только одну строку из набора дубликатов, что сложно в SQL (это становится проще в PL / SQL). В этом случае rowid полезен.
Теги:
rowid

2 ответа

0

Если вся строка дублируется и вы хотите удалить все, кроме одной копии, в SQL нет простого способа выбрать строки, которые вы хотите удалить, не используя системный адрес строки.

Использование Ronnis' PRICES таблицы в качестве примера, мы видим, что есть три строки для B, которые являются точными копиями:

ID PRICE UPD_DATE
-- ----- -----------
A      7 10/04/2018
B      8 09/04/2018
B      8 09/04/2018
B      8 09/04/2018
C      7 04/04/2018
C      8 05/04/2018
C      9 06/04/2018

Хотя мы могли бы использовать что-то вроде

delete prices where id = 'B' and rownum <= 2;

это нехорошее решение, так как мы должны знать идентификаторы и подсчеты и применять к одному ID за раз.

Мы можем удалить их без явного указания rowid с помощью PL/SQL:

declare
    cursor c_prices is
        select id, price
              , row_number() over (partition by id order by upd_date desc) as seq
        from   prices
        for update;
begin
    for r in c_prices
    loop
        if r.seq > 1 then
            delete prices where current of c_prices;
        end if;
    end loop;
end;

хотя, конечно, внутри, where current of синтаксиса используется rowid.

Использование rowid явно делает это намного проще:

delete prices where rowid in
( select lag(rowid) over (partition by id order by upd_date) from prices );

Это находит все "предыдущие" ряды по порядку даты и удаляет соответствующие строки. Последняя строка в каждом наборе не будет отображаться в этом списке и поэтому не будет удалена.

0

ROWID - это внутренний идентификатор строки, используемый Oracle для поиска физической записи. Поэтому, даже если у вас могут быть повторяющиеся значения для вашего "ID", каждая запись ROWID будет по-прежнему уникальной.

create table prices(
   id       varchar2(15) not null
  ,price    number       not null
  ,upd_date date         not null
--  ,primary key(id)
);

ROWID                ID PRICE UPD_DATE
------------------   -- ----- ----------
AChTgbADaAAFgxYAAA   A  7     2018-04-10

AChTgbADaAAFgxYAAB   B  8     2018-04-09
AChTgbADaAAFgxYAAC   B  8     2018-04-09
AChTgbADaAAFgxYAAD   B  8     2018-04-09

AChTgbADaAAFgxYAAE   C  9     2018-04-06
AChTgbADaAAFgxYAAF   C  8     2018-04-05
AChTgbADaAAFgxYAAG   C  7     2018-04-04

MAX (rowid) в группе часто является самой последней вставленной записью, но это предположение неверно слишком часто, чтобы опираться на производственный код. На него можно полагаться только на удаление идеального дубликата. Идеальный дубликат - это тот, в котором select distinct * результат в одной записи. Для всех других целей вам нужен дискриминатор. Столбец дискриминатора может использоваться, чтобы разделить две записи, например, с датой обновления, которая указывает время изменения.

Если вы удалите дубликат моей таблицы с типичным подходом ROWID, вы бы неправильно удалили самую последнюю цену 9 (о чем свидетельствует upd_date).

delete
  from prices
 where rowid not in(
        select max(rowid)
          from prices
      group by id);

Лучшим подходом было бы использовать дискриминатор сначала, а затем в качестве последнего средства использовать ROWID.

delete 
  from prices
 where rowid in(
        select rid
          from (select rowid as rid
                      ,row_number() over(            -- Assign a sequence number
                          partition by id            -- Group rows by ID
                              order by upd_date desc -- Sort them by upd_date first  
                                      ,rowid desc    -- Then by ROWID
                      ) as rn
                   from prices
               )
     -- The most recent record will be rn = 1.
     -- The second most recent record will be rn = 2, etcetera
        where rn > 1 -- Select only the duplicates ("after" the most recent one record
       );

Ещё вопросы

Сообщество Overcoder
Наверх
Меню