oracle儲存過程 更改字段型別

2021-09-08 09:09:24 字數 4432 閱讀 4459

一、問題說明:在專案開發過程中,有時需要將多張表做union操作,會發現由於個別表的字段不一致,造成union語句查詢報錯。

這時有以下的解決方法:

1.較為簡單:將少量的不一致字段,使用to_number、to_date等方式作下處理。這樣能夠確保查詢操作正常

2.較為複雜:更改少量不一致欄位的字段型別,與多數表中的字段型別保持一致

簡單的方法就不用說了,下面看下複雜的情況該如何操作。接下來寫乙個儲存過程,更改資料庫中表的字段型別(同時要保證資料不能被刪除掉,前提:該資料型別轉換本身不會丟失精度):

以mytest表(建表及插入測試資料的語句附在文末)為例,

mytest表中sbirthday原本打算建立成date型別,實際卻是varchar2型別;

smoney原本打算建立成number型別,實際卻是varchar2型別

二、具體實現

需要分別執行下面3段臨時的儲存過程,這樣就能將sbirthday和smoney欄位轉換為原有的資料型別

begin

--建立臨時表

execute immediate

'create table temp_table(

sid number,

sbirthday date,

smoney number

)';--將已有表的資料備份下

execute immediate

'create table mytest_bak as

select * from mytest';

end;

begin

--把資料插到臨時表中

insert into temp_table(sid, sbirthday, smoney)

select pe.sid, to_date(pe.sbirthday,'yyyy-mm-dd'), pe.smoney from mytest pe;

--刪除原有表的資料

update mytest set sbirthday = null, smoney = null;

--修改原有表的資料型別

execute immediate 'alter table mytest modify sbirthday date';

execute immediate 'alter table mytest modify smoney number';

--修改原有表的資料

update mytest pe set (pe.sbirthday, pe.smoney) =

(select tt.sbirthday, tt.smoney from temp_table tt where tt.sid = pe.sid);

commit;

end;

--刪之前先找幾個資料驗證一下

begin

--刪除臨時表

execute immediate 'drop table temp_table';

--刪除備份表

execute immediate 'drop table mytest_bak';

end;

正因為實際操作起來步驟稍顯麻煩,大部分情況下不會選擇更改字段型別,而是選擇直接改sql語句。

現在把這個邏輯抽象成帶參的儲存過程,這樣以後更改欄位的資料型別就很方便了。儲存過程如下:

create or replace procedure changedatatype

(tablename varchar2,

primkeyname varchar2,

changefieldname varchar2,

totype varchar2

)authid current_user as

/** 將某張表中指定欄位更改為特定資料型別

* 引數:

* tablename 需要操作的表

* primkeyname 需要操作的表的主鍵名

* changefieldname 需要操作的字段

* totype 操作的字段需要轉換成的資料型別

**/bakfieldselectstr varchar2(300); --需要轉換的字段在插入臨時表時的查詢字串

begin

--建立臨時表

execute immediate

'create table temp_table(

sid number,'

||changefieldname||' '||totype

||')';

--把資料插到臨時表中

if totype = 'date' then --日期型別

bakfieldselectstr:='to_date(pe.'||changefieldname||',''yyyy-mm-dd'')';

else --普通型別

bakfieldselectstr:='pe.'||changefieldname;

end if;

execute immediate

'insert into temp_table(sid, '||changefieldname||')

select pe.'||primkeyname||','||bakfieldselectstr||' from '||tablename||' pe';

--刪除原有表的資料

execute immediate

'update '||tablename||' set '||changefieldname||' = null';

--修改原有表的資料型別

execute immediate 'alter table '||tablename||' modify '||changefieldname||' '||totype;

--修改原有表的資料

execute immediate

'update '||tablename||' pe set (pe.'||changefieldname||') =

(select tt.'||changefieldname||' from temp_table tt where tt.'||primkeyname||' = pe.'||primkeyname||')';

commit;

--刪除臨時表

execute immediate 'drop table temp_table';

end;

測試使用,能夠正常將字段型別進行轉換,並保留資料:

begin

changedatatype('mytest','sid','sbirthday','date');

changedatatype('mytest','sid','smoney','number');

end;

附:建表及插入測試資料的語句

-- create table

create table mytest

( sid number not null,

sname varchar2(10) not null,

s*** char(2),

sbirthday varchar2(100),

smoney varchar2(100)

);-- add comments to the columns

comment on column mytest.sid

is '主鍵';

comment on column mytest.sname

is '姓名';

comment on column mytest.s***

is '性別';

comment on column mytest.sbirthday

is '生日';

comment on column mytest.smoney

is '金額';

--插入測試資料

insert into mytest (sid, sname, s***, sbirthday, smoney)

values (1, '張三', '男', '1991-08-01', '1000');

insert into mytest (sid, sname, s***, sbirthday, smoney)

values (2, '李四', '男', '1992-05-01', '2000');

insert into mytest (sid, sname, s***, sbirthday, smoney)

values (3, '小紅', '女', '1993-03-05', '3000');

commit;

Oracle常見的字段更改

新增日期型別 alter table tar grp import info add mydate date 新增字串型別,並指定長度為4000 alter table tar grp import info add mycloumn varchar2 4000 字段長度更改 alter table...

Oracle批量修改表字段型別(儲存過程)

declare cursor temp is select creditzs code,attribute code,attribute info type,t.id from credit directory attribute t,credit directory tree e where t....

Oracle儲存過程呼叫儲存過程

oracle儲存過程呼叫有返回結果集的儲存過程一般用光標的方式,宣告乙個游標,把結果集放到游標裡面,然後迴圈游標 declare newcs sys refcursor cs1 number cs2 number cstype table rowtype table列的個數和newcs返回的個數一樣...