【问题标题】:Delete Oracle rows based on size根据大小删除 Oracle 行
【发布时间】:2016-05-30 19:42:32
【问题描述】:

我有这张 Oracle 表,当我达到 2000 行数据时,我想不时清理它:

CREATE TABLE AGENT_HISTORY(
  EVENT_ID INTEGER NOT NULL,
  AGENT_ID INTEGER NOT NULL,
  EVENT_DATE DATE NOT NULL
)
/

当表达到 2000 行时,如何从表中删除最旧的行?

【问题讨论】:

    标签: sql oracle oracle11g oracle10g


    【解决方案1】:

    创建一个 DBMS_JOB 或 DBMS_SCHEDULER,在一定的时间间隔后启动并调用一个过程。在该过程中检查计数并根据 event_date 删除行。


    对不起,我直到现在才看到你的评论。这是您正在寻找的代码。确保您有创建调度程序和作业的授权。此代码假定 event_id 是 #s 序列并与 event_date 保持一致。否则,根据时间和 ID 或您的选择更改排名。您也可以更改时间间隔。检查 DBMS_SCHEDULER 包文档是否有任何错误和更正。

    create or replace procedure proc_house_keeping is
    begin
      delete
        from (
        select rank() over (order by event_id desc) rnk
          from agent_history 
       )
        where rnk > 2000;
      commit;
    end;
    /
    
    begin
      dbms_scheduler.create_program(
      program_name   => 'PROG_HOUSE_KEEPING',
      program_type   => 'STORED_PROCEDURE',
      program_action => 'PROC_HOUSE_KEEPING',
      number_of_arguments => 0,
      enabled        => FALSE,
      comments       => 'Procedure to delete rows greater than 2000');
    end;
    /
    
    begin
      dbms_scheduler.create_job(
          job_name => 'table_house_keeping',
          program_name => 'PROG_HOUSE_KEEPING',
          start_date => dbms_scheduler.stime,
          repeat_interval => 'FREQ=MINUTELY;INTERVAL=1',
          end_date => dbms_scheduler.stime+1,
          enabled => false,
          auto_drop => false,
          comments => 'table house keeping, runs every minute');
    end;
    /
    

    【讨论】:

      【解决方案2】:

      一种方法可能是在您的表中添加一个触发器,以便它在每个 INSERT 语句中检查并删除最旧的行;例如,假设不超过 3 行:

      CREATE OR REPLACE TRIGGER DELETE_3
      AFTER INSERT ON AGENT_HISTORY
      DECLARE
          vNum    number;
          minDate date;
      BEGIN
      
          delete AGENT_HISTORY
          where (event_id, agent_id, event_date) in
                   (  select event_id, agent_id, event_date
                      from (        
                              select event_id, agent_id, event_date, row_number() over (order by event_date desc) num
                              from AGENT_HISTORY
                           )
                      where num > 3 /* MAX NUMBER OF ROWS = 3*/
                   );
      END;
      

      假设我们插入 5 行:

      SQL> begin
        2      insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 1, 1, sysdate);
        3      dbms_lock.sleep(1);
        4      insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 2, 2, sysdate);
        5      dbms_lock.sleep(1);
        6      insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 3, 3, sysdate);
        7      dbms_lock.sleep(1);
        8      insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 4, 4, sysdate);
        9      dbms_lock.sleep(1);
       10      insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 5, 5, sysdate);
       11      commit;
       12  end;
       13  /
      
      PL/SQL procedure successfully completed.
      

      我们只有最新的 3 个:

      SQL> select * from  AGENT_HISTORY;
      
        EVENT_ID   AGENT_ID EVENT_DATE
      ---------- ---------- ---------------------------------------------------------------------------
               3          3 18-FEB-16 17:05:24,000000
               4          4 18-FEB-16 17:05:25,000000
               5          5 18-FEB-16 17:05:26,000000
      

      【讨论】:

        【解决方案3】:

        您可以使用以下查询删除除最新的 2000 行之外的所有行:

        DELETE FROM agent_history a
         WHERE 2000 < ( SELECT COUNT(1) cnt FROM agent_history b WHERE b.event_date < a.event_date )
        

        查询检查表 (a) 中的每一行,以查看有多少行的 event_date LESS 小于该行。如果少于它的行数超过 2000 行,那么它将删除该行。

        如果这不起作用,请告诉我。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-06
          • 1970-01-01
          • 2017-11-23
          相关资源
          最近更新 更多