Oracle truncate table xx 急救...

mc_dv 2015-01-06 11:59:30
用了truncate table 表 .. 把表误删了, 现在用时间戳和scn 都不能恢复,提示表定义更改 , 然后通过重新建立索引,主键什么的, 还是提示表定义更改。 请问还有办法还原数据吗 .
...全文
130 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
itage 2015-11-29
  • 打赏
  • 举报
回复
只要数据没有覆盖,Dbseeker for Oracle Database可以轻松找回数据。 Dbseeker for Oracle Database是一款用Java语言开发的Oracle数据库恢复软件。Dbseeker能够绕过Oracle读数据引擎,直接扫描数据文件的数据块, 分析数据块格式,读取数据库中的表记录。因此,在由于各种原因引起的数据库不能打开或者数据库中的表被DROP,TRUNCATE,DELETE后,而且没有备份的情况下,使用Dbseeker能够及时找回数据表记录。 最新版本请访问http://www.dbseeker.com
小灰狼W 2015-01-06
  • 打赏
  • 举报
回复
找以前的备份来恢复吧
mc_dv 2015-01-06
  • 打赏
  • 举报
回复
引用 3 楼 bw555 的回复:
翻了翻以前的文档,还真找到一个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

....... 没看懂, 找前几天的备份恢复算了 .....
mc_dv 2015-01-06
  • 打赏
  • 举报
回复
引用 楼主 a419816897 的回复:
用了truncate table 表 .. 把表误删了, 现在用时间戳和scn 都不能恢复,提示表定义更改 , 然后通过重新建立索引,主键什么的, 还是提示表定义更改。 请问还有办法还原数据吗 .
哦, 谢谢 .
bw555 2015-01-06
  • 打赏
  • 举报
回复
翻了翻以前的文档,还真找到一个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

bw555 2015-01-06
  • 打赏
  • 举报
回复
只能找以前的备份恢复了

17,377

社区成员

发帖
与我相关
我的任务
社区描述
Oracle 基础和管理
社区管理员
  • 基础和管理社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧