当前位置: 代码迷 >> Oracle管理 >> Oracle truncate table xx 抢救.
  详细解决方案

Oracle truncate table xx 抢救.

热度:408   发布时间:2016-04-24 04:09:34.0
Oracle truncate table xx 急救...
  用了truncate table 表  .. 把表误删了, 现在用时间戳和scn 都不能恢复,提示表定义更改 ,     然后通过重新建立索引,主键什么的, 还是提示表定义更改。 请问还有办法还原数据吗 .
------解决思路----------------------
找以前的备份来恢复吧
------解决思路----------------------
只能找以前的备份恢复了
------解决思路----------------------
翻了翻以前的文档,还真找到一个truncate的恢复文档,参考
/*
  truncate表后的数据恢复测试(对于drop purge也可以仿照此方法)
*/

--step1:首次创建测试表并删除
create table trunc_tab(id int,name char(800)) pctfree 99;

begin
  for i in 1 .. 10 loop
    insert into trunc_tab
    values
      (i, dbms_random.string('p', 10) 
------解决思路----------------------
 '中国');
  end loop;
  commit;
end;

select count(distinct dbms_rowid.rowid_block_number(rowid)) cnt
  from trunc_tab;

drop table trunc_tab;

--step2:再次创建测试表
create table trunc_tab(id int,name char(800)) pctfree 99;

begin
  for i in 1 .. 100 loop
    insert into trunc_tab
    values
      (i, dbms_random.string('p', 10) 
------解决思路----------------------
 '中国');
  end loop;
  commit;
end;
--确定块数
select count(distinct dbms_rowid.rowid_block_number(rowid)) cnt
  from trunc_tab;

--step3:创建参照表  
create table trunc_tab_ref as select * from trunc_tab;

--step4:truncate待恢复表
truncate table trunc_tab;

--step5:立即关闭数据库,并启动到受限模式

--step6:查看表头
select ds.header_file, ds.header_block
  from dba_segments ds
 where segment_name = 'TRUNC_TAB'
 order by 2;

alter system dump datafile 6 block 1083;
--当然我们从dump出来的块头中是再也看不到
--extent的历史信息,也许你会想到以sys来
--闪回查询dba_extents,但是dba_extents
--查不到这些信息(我也纳闷为什么不可以)

--step7:查看当前区中一个数据块内容 
alter system dump datafile 6 block 1086; 
--我们要找到是段信息:
seg/obj: 0xba46
--这个信息是关键,truncate表时oracle只是将对应的
--块标记为可用状态,而并不会清空块中实际内容

--step8:按块顺序dump出trunc_tab表所在数据文件所有块内容

--step9:创建外部表以读取dump出的文件内容
 create table dump_block_contents
 (text varchar2(4000)
 )
 organization external
 (type oracle_loader
 default directory DATA_PUMP_DIR
 access parameters
 (records delimited by newline
 fields (text (1:4000) char))
 location ('zhangyu_ora_3484.trc'));
 

--step9:创建临时表(共解析出的二进制字段使用)
create table temp(id number,name clob);

--step10:创建解析文本的存储过程
declare
  cursor c_text is
    select text from t_alert;
  v_text    c_text%rowtype;
  col_value varchar2(32767);
  cnt_flag  number := 0;
begin

  open c_text;

  loop
    fetch c_text
      into v_text;
    exit when c_text%notfound;
    if regexp_instr(v_text.text, 'seg[/]obj:[ ]{0,}0xba46') > 0 then
      loop
      
        fetch c_text
          into v_text;
        exit when c_text%notfound;
        if regexp_instr(v_text.text, 'col[ ]{1,}[[:digit:]]{1,}[ ]{0,}:') > 0 then
          col_value := replace(regexp_replace(v_text.text,
                                              '.+[]][ ]{0,}(.*)$',
                                              '\1'),
                               ' ');
        
          <<next_col>>
          begin
            null;
          end;
          loop
            fetch c_text
              into v_text;
            exit when c_text%notfound;
            if regexp_instr(v_text.text,
                            'col[ ]{1,}[[:digit:]]{1,}[ ]{0,}:') = 0 and
               v_text.text <> 'end_of_block_dump' then
              col_value := col_value 
------解决思路----------------------
 replace(regexp_replace(v_text.text,
                                                               '.+[]][ ]{0,}(.*)$',
                                                               '\1'),
                                                ' ');
            elsif v_text.text = 'end_of_block_dump' then
              insert into temp (id, name) values (cnt_flag, col_value);
              cnt_flag := cnt_flag + 1;
              goto next_block;
            elsif regexp_instr(v_text.text,
                               'col[ ]{1,}[[:digit:]]{1,}[ ]{0,}:') > 0 then
              insert into temp (id, name) values (cnt_flag, col_value);
              cnt_flag  := cnt_flag + 1;
              col_value := replace(regexp_replace(v_text.text,
                                                  '.+[]][ ]{0,}(.*)$',
                                                  '\1'),
                                   ' ');
              goto next_col;
            else
              null;
            end if;
          end loop;
        else
          null;
        end if;
      end loop;
    else
      null;
    end if;
    <<next_block>>
    begin
      null;
    end;
  end loop;

  close c_text;

  commit;

end;


--step11:根据解析出的二进制字段信息生成insert语句
with t as
(
  select wm_concat('q''a' 
------解决思路----------------------
 col 
------解决思路----------------------
 'a''') over(partition by group# order by id) col1,
         id,
         group#,
         max(id) over(partition by group#) as mx_id
    from (select case
                   when mod(rownum, 2) = 1 then
                    to_char(utl_raw.cast_to_number(to_char(name)))
                   else
                    utl_raw.cast_to_varchar2(to_char(name))
                 end as col,
                 ntile(100) over(order by null) as group#,
                 rownum id
            from (select * from temp order by id))
)
select 'insert into trunc_tab(id,name) values(' 
------解决思路----------------------
 col1 
------解决思路----------------------
 ');'
  from t
 where id = mx_id; 
 
--step12:在sql*plus中执行生成的insert语句 
set define off;
@filename.sql

 
  相关解决方案