Oracle中不进行子选择可以删除最近的记录吗?

发布于 2024-11-17 04:03:24 字数 251 浏览 1 评论 0原文

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

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

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

I want a SQL statement to delete the most recent record in a table. Here's my idea:

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

But it seems like there is likely a way to do this without a sub-select, which might be inefficient. (Efficiency isn't actually important in my case, I just want to know the simplest, most readable way to code this.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

第几種人 2024-11-24 04:03:24

最易读的方式可能是你写的。但根据各种因素,这可能会非常浪费。特别是,如果 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;
/

The most readable way is probably what you wrote. But it can be very wasteful depending on various factors. In particular, if there is no index on process_date it likely has to do 2 full table scans.

The difficulty in writing something that is both simple and more efficient, is that any view of the table that includes a ranking or ordering will also not allow modifications.

Here's one alternate way to approach it, using PL/SQL, that will probably be more efficient in some cases but is clearly less readable.

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;
/

Also note this potentially produces different results from your statement if there can be multiple rows with the same process_date value. To make it handle duplicates requires a little more complexity:

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;
/
吻泪 2024-11-24 04:03:24

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

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

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

I knew there was a better way that I wasn't thinking of.

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

Again, this will only delete a single row, even if there are multiple rows with the maximum value, so depending on your data it can produce different results than the original query.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文