我可以删除Oracle中没有子选择的最新记录吗?

时间:2011-06-24 13:31:01

标签: sql oracle subquery

我想要一个SQL语句来删除表中的最新记录。这是我的想法:

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

但似乎有一种方法可以在没有子选择的情况下做到这一点,这可能是低效的。 (效率在我的情况下并不重要,我只是想知道最简单,最易读的编码方式。)

2 个答案:

答案 0 :(得分:3)

最可读的方式可能就是你写的。但取决于各种因素,它可能非常浪费。特别是,如果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;
/

答案 1 :(得分:3)

我知道有一种更好的方法,我没想到。

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

同样,这只会删除一行,即使有多行具有最大值,因此根据您的数据,它可以产生与原始查询不同的结果。