【问题标题】:create columns in existing table and populate data using procedure在现有表中创建列并使用过程填充数据
【发布时间】:2021-03-09 19:06:15
【问题描述】:

我会尽量缩短查询。这涉及 2 个表 - 我们称它们为 staging_data 和 audit_data。 STAGING_DATA 有 3 列:

  • user_no 与数据类型编号,
  • update_date_time 数据类型为 DD-MON-YYYY HH24:MI:SS 格式的日期
  • status_code 是 varchar(1)。

audit_data 表也有相同的 3 列。要求是向 audit_data 表添加 3 列

  • seq_no(每个用户都是唯一的),
  • active_from(不带时间格式的日期类型)
  • active_to(不带时间格式的日期类型)。

有一个将数据从 staging_data 插入到 audit_data 的过程。 表 audit_data 示例

审计表中的数据应如下所示:

对于 user_no 523 的下一条记录(假设 update_date_time 为 '23-Nov-2020 10:20')seq_no 变为 3,active_from_date 变为 '23-Nov-2020',active_to 变为 31-Dec-99 和 active_to seq_no 2 的 user_no 523 变为“2020 年 11 月 22 日”。所以数据应该是这样的:

以浅绿色突出显示稍后将添加的第三条记录。

所以这是我的解决方案:我建议使用row_number() over(partition by user_no) 分析函数来获取每个用户的 seq_no。我想基于它创建一个视图,但老板不想要一个视图。他严格地想要使用一个程序。程序应检查 user_no 是否存在(在本例中为 523)。如果存在,则 seq_no 增加,并且 523 的先前记录的 active_to 更改为最新的 active_from - 1 日期。老实说 - 我不知道如何在程序中实现这一点。我知道我可以使用我对视图的查询来创建一个游标。但是添加 seq_no 和更改 active_to 日期让我感到困惑。任何人都可以指导我正确的方向吗?如果我遗漏了任何其他细节,我提前道歉。现在是午夜了,经过 8 个小时的绞尽脑汁,我非常饿!

编辑 3 月 11 日:这是我编写的将数据插入审计表的过程的代码,以应对特定 user_no 在审计表中没有记录的情况:

create or replace procedure test_aud IS
  user_found_audit number;
  lv_user_no AUDIT_DATA.user_no%TYPE;
  cursor member_no is select distinct user_no from STAGING_DATA;
begin
  open member_no;
  loop
    fetch member_no into lv_user_no;
    exit when member_no%notfound;
    select count(*) into user_found_audit from AUDIT_DATA where user_no = lv_user_no;
    if user_found_audit = 0 then
      insert into AUDIT_DATA(user_no, update_date_time,status_code, seq_no, last_update_date, active_from, active_to)
      select user_no, update_date_time,status_code,row_number() over(partition by user_no order by UPDATE_DATE_TIME) as seqno,
      to_char(trunc(update_date_time),'DD-MON-YYYY'),
      to_char(trunc(update_date_time),'DD-MON-YYYY'),
      lead(to_char(trunc(update_date_time)-1,'DD-MON-YYYY'),1,'31-DEC-99') over(PARTITION BY user_no ORDER BY UPDATE_DATE_TIME) from STAGING_DATA where user_no = lv_user_no;
      commit;
    else
      dbms_output.put_line(lv_user_no||' exists in audit table');
      -- to code the block when user_no exists, involves an update and insert
    end if;
        
  end loop;
  
  close member_no;
  
end;
/

【问题讨论】:

    标签: stored-procedures plsql


    【解决方案1】:

    嗯,你需要收集一些东西。最新的阶段行和最新的审计行。然后只需生成新的审计信息并更新以前的最新信息即可。下面做了几个简化的假设:

    1. 只有给定 user_no 的最新阶段数据需要处理为 所有先前的都已处理,但是它不假定该阶段 表已清空。
    2. “Y”和“N”状态码的顺序是正确的 那种方式。事实上,它甚至不检查值。
    3. 它不需要关注固有的竞争条件。这 条件源自生成为 Max()+1 的 seq_no。这 结构实际上保证了重复最终将是 已创建。

    嵌套过程“建立审核”完成所有实际工作。其余的只是支持字符,包括几个仅用于调试目的的字符。见fiddle

    create or replace 
    procedure generate_stage_audit(user_no_in staging_data.user_no%type) 
    as 
        k_end_of_time constant date := date '9999-12-31'; 
        l_latest_user_stage staging_data%rowtype;
        l_latest_user_audit audit_data%rowtype;  
        
        procedure establish_audit
        is 
        begin
           insert into audit_data(user_no, update_date_time, status_code 
                                 ,seq_no, active_from, active_to)                     
               select l_latest_user_stage.user_no
                    , l_latest_user_stage.update_date_time
                    , l_latest_user_stage.status_code
                    , coalesce(l_latest_user_audit.seq_no,0) + 1
                    , trunc(l_latest_user_stage.update_date_time)               
                    , k_end_of_time
                 from dual;
                  
           update audit_data 
              set active_to = trunc(l_latest_user_stage.update_date_time - 1)
             where user_no = l_latest_user_audit.user_no 
               and seq_no  = l_latest_user_audit.seq_no; 
        end establish_audit;
        
        procedure retrieve_latest_stage
        is 
        begin
            select * 
              into l_latest_user_stage
              from staging_data  
             where (user_no,  update_date_time) =
                   ( select user_no,  max(update_date_time)
                       from staging_data                  
                      where user_no = user_no_in
                      group by user_no
                   );    
        end retrieve_latest_stage; 
        
        procedure retrieve_latest_audit
        is 
        begin
            select * 
             into l_latest_user_audit
             from audit_data  
            where (user_no, seq_no) =
                  ( select user_no,  max(seq_no)
                      from audit_data             
                     where user_no = user_no_in
                     group by user_no
                  );
        exception
          when no_data_found then 
               null;           
        end retrieve_latest_audit;  
            
        ---- for debugging ---   
        procedure show_stage 
        is 
        begin 
            dbms_output.put_line('-------- Stage Row -------');
            dbms_output.put_line('         user_no==>' || to_char(l_latest_user_stage.user_no));
            dbms_output.put_line('update_date_time==>' || to_char(l_latest_user_stage.update_date_time));
            dbms_output.put_line('     status_code==>' || to_char(l_latest_user_stage.status_code));
        end show_stage;
       
        procedure show_audit 
        is 
        begin 
            dbms_output.put_line('-------- Audit Row -------');
            dbms_output.put_line('         user_no==>' || to_char(l_latest_user_audit.user_no));
            dbms_output.put_line('update_date_time==>' || to_char(l_latest_user_audit.update_date_time));
            dbms_output.put_line('     status_code==>' || to_char(l_latest_user_audit.status_code));
            dbms_output.put_line('          seq_no==>' || to_char(l_latest_user_audit.seq_no));      
            dbms_output.put_line('     active_from==>' || to_char(l_latest_user_audit.active_from)); 
            dbms_output.put_line('       active_to==>' || to_char(l_latest_user_audit.active_to));      
        end show_audit;
     
    begin  -- the main event
        retrieve_latest_stage;
        show_stage; 
        
        retrieve_latest_audit; 
        show_audit;
       
        establish_audit; 
    end generate_stage_audit;  
    

    几个警告:

    • 您似乎很想使用字符串数据类型进行审计 列 Active_Form 和 Active_to ,因为你试图然后声明 “没有时间的日期类型”。但是没有这样的数据类型 甲骨文;时间是所有日期的一部分。 不要这样做,将它们存储为 标准日期。 (注意日期不以任何格式存储,而是以 内部结构。格式是严格的视觉表示)。 只需使用查询格式或通过设置丢弃时间 nls_date_format。
    • 您可能很想通过触发器转换调用它。 不要, 它可能会导致“ORA-04091: Table is mutating” 例外。

    【讨论】:

    • 感谢您的努力,但编译时出现错误。声明了 2 个行类型后,我们不必为每个行类型声明一个游标吗?
    • 顺便说一句,我为 audit_data 表中没有特定 user_no 的数据的情况编写了一个过程:确定在粘贴过程代码时出错。有人知道在评论中发布我的代码的任何选项吗?还是我应该编辑我的问题?
    • 编辑问题。不要在 as 注释中发布代码(一般 1 行即可)。进一步说您正在编译或以其他方式完全没用。需要的是细节:确切的错误和位置。与“不起作用”相同。有发布结果和说明为什么它是错误的。无论哪种情况,您都可能希望发表评论,表明您已更新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 1970-01-01
    • 2012-04-11
    • 1970-01-01
    相关资源
    最近更新 更多