Можно ли удалить самую последнюю запись без дополнительного выбора в Oracle? - PullRequest
1 голос
/ 24 июня 2011

Я хочу, чтобы инструкция SQL удаляла самую последнюю запись в таблице. Вот моя идея:

delete from daily_statistics 
where process_date = (
  select max(process_date) 
  from daily_statistics
);

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

Ответы [ 2 ]

3 голосов
/ 24 июня 2011

Я знал, что есть лучший способ, о котором я не думал.

delete from daily_statistics 
where rowid = (
  select max(rowid) keep (dense_rank first order by process_date desc) 
  from daily_statistics
);

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

3 голосов
/ 24 июня 2011

Наиболее читаемый способ - это, вероятно, то, что вы написали. Но это может быть очень расточительным в зависимости от различных факторов. В частности, если на process_date нет индекса, он, вероятно, должен выполнить 2 полных сканирования таблицы.

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

Вот еще один альтернативный подход к нему, использующий PL / SQL, который, вероятно, будет более эффективным в некоторых случаях, но явно менее читабельным.

DECLARE
  CURSOR delete_cur IS
    SELECT /*+ FIRST_ROWS(1) */
      NULL
    FROM daily_statistics
    ORDER BY process_date DESC
    FOR UPDATE;
  trash  CHAR(1);
BEGIN
  OPEN delete_cur;
  FETCH delete_cur INTO trash;
  IF delete_cur%FOUND THEN
    DELETE FROM daily_statistics WHERE CURRENT OF delete_cur;
  END IF;
  CLOSE delete_cur;
END;
/

Также обратите внимание, что это может привести к другим результатам из вашего оператора, если может быть несколько строк с одинаковым значением process_date. Для обработки дубликатов требуется немного больше сложности:

DECLARE
  CURSOR delete_cur IS
    SELECT /*+ FIRST_ROWS(1) */
      process_date
    FROM daily_statistics
    ORDER BY process_date DESC
    FOR UPDATE;
  del_date  DATE;
  next_date DATE;
BEGIN
  OPEN delete_cur;
  FETCH delete_cur INTO del_date;
  IF delete_cur%FOUND THEN
    DELETE FROM daily_statistics WHERE CURRENT OF delete_cur;
  END IF;
  LOOP
    FETCH delete_cur INTO next_date;
    EXIT WHEN delete_cur%NOTFOUND OR next_date <> del_date;
    DELETE FROM daily_statistics WHERE CURRENT OF delete_cur;
  END LOOP;
  CLOSE delete_cur;
END;
/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...