您的位置:首页 > 数据库 > Oracle

oracle中varchar2字段转clob字段,并提供读取方法。

2014-06-14 15:01 393 查看


转载自:http://my.oschina.net/guyfar/blog/73837


问题描述

CMS系统中有一个表的字段(如:content)是varchar2类型(最多只能存储4000字符),不够用了,因此将其改为clob类型(支持4G存储量)。

如果该字段content列不为空的话,不能直接通过sql语句修改其字段类型,会报ORA-22858的错误,如图所示:





解决方法:

1.首先创建一个clob的临时字段:

1
alter
table
table_name
add
(tmp
clob);
2.然后将content字段内容全部复制到tmp字段中,具体方法请见:

http://my.oschina.net/guyfar/blog/73829

3.修改content字段名为content_bak,将tmp的字段名改为content即可。

1
alter
table
table_name
rename
column
content
to
content_bak;
2
3
alter
table
table_name
rename
column
tmp
to
content;
到这里就完成了字段类型的转换。

虽然数据类型已经转换完成,会发现调用此字段的程序会报错。那是因为通过sql查询出的clob字段是对象类型,因此会报错。

我是通过存储过程来调用的,存储过程如下:

01
create
or
replace
function
getclob(
02
03
table_name 
in
varchar2,
04
05
field_id
in
varchar2,
06
07
field_name
in
varchar2,
08
09
v_id
in
number,
10
11
v_pos
in
number)
return
varchar2
12
13
is
14
15
lobloc
clob;
16
17
buffer
varchar2(32767);
18
19
amount
number :=2000;
20
21
offset
number :=1;
22
23
query_str
varchar2(1000);
24
25
begin
26
27
query_str
:=
'select
'
||field_name||
'
from '
||table_name||
'
where '
||field_id||
'=
:id '
;
28
29
--initialize
buffer with data to be found
30
31
EXECUTE
IMMEDIATE
query_str
INTO
lobloc
USING v_id;
32
33
offset:=offset+(v_pos-1)*2000;
34
35
--read
2000 varchar2 from the buffer
36
37
dbms_lob.
read
(lobloc,amount,offset,buffer);
38
39
 
return
buffer;
40
41
exception
42
43
 
when
no_data_found
then
44
45
 
return
buffer;
46
47
end
;
调用存储过程的PHP方法:

01
function
edt_disp_getclob(
$id
,
$field_id
,
$field_name
,
$len
)
{
02
 
$a
=
2000;
03
 
$b
=
$a
/
2;
04
 
if
((
$len
%
$b
)
==0) {
05
$maxpage
=
floor
(
$len
/
$a
);
06
 
}
else
{
07
$maxpage
=
floor
(
$len
/
$a
)
+ 1;
08
 
}
09
 
$i
=
0;
10
 
$con
=
""
;
11
 
$a
=
new
DB_Sql
();
12
 
while
(
$i
<
$maxpage
)
{
13
$i
=
$i
+
1;
14
$sql
=
"select
getclob('table_name','$field_id','$field_name','$id','$i') as h from dual"
;
15
//echo
$sql."<BR>";exit;
16
$a
->query
(
$sql
);
17
if
(
$a
->next_record
()) {
18
  
$h
=
$a
->Record
[
"h"
];
19
}
20
$con
=
$con
.
$h
;
21
 
}
22
 
if
(!
empty
(
$con
))
{
23
$a
->disconnect
();
24
 
}
25
 
return
$con
;
26
}
调用:

1
$con
=
edt_disp_getclob(
$id
,
'id'
,
'con'
,
$con_len
);
参数说明:

$id :要查询的行

id:按ID查询

con :字段名称

$con_len :要查询的字段长度(提前通过sql查出)

至此,所有改动完成。

CREATE OR REPLACE PROCEDURE prc_read_clob (

table_name INVARCHAR2,

clob_column_name INVARCHAR2,

primary_Key_Column_namesINVARCHAR2,

primary_key_values INVARCHAR2,

offset_i INNUMBER,

read_length_i INNUMBER,

RES OUT VARCHAR2,

total_lengthOUT NUMBER)

AS

/**

Autor:Hanks_gao.

Create Date:2008/12/10

Description:This procedure is to read clob value by conditions

--------------------------------------------------------------

-----------------Parameters descritption----------------------

table_name: The table that contains clob/blob columns(表名)

clob_column_name : Clob/blob column name of table_name(类型为clob的字段名)

primary_key_column_names : The columns seperated by '}' that can fix only one row data (that is primary key) (主键名,以'}'分隔的字符串)

primary_key_values : The primary keyes values that seperated by '}'(主键键值,以'}'分隔的字符串)

offset_i : The offset of reading clob data(要读取的位移量)

read_length_i : The length of reading clob data per times(要读取的长度)

res : Return value that can be referenced by application(读取的结果)

total_length : The total length of readed clob data(数据库查询到的clob数据的总长度)

-----------------End Parameters descritption------------------

*/

tmpPrimaryKeysVARCHAR2 (2000); --To save primary_Key_Column_names temporarily(暂存主键,主键是以'}'分隔的字符串)

tmpPrimaryKeyValuesVARCHAR2 (2000); --To save primary_key_values temporarily(暂存主键键值,以'}'分隔的字符串)

iNUMBER; --循环控制变量

tmpReadLength NUMBER; --暂存要读取的长度

sqlStrVARCHAR2 (6000); --Query string(查询字符串)

sqlConVARCHAR2 (5000); --Query condition(查询条件)

TYPE tmparray IS TABLE OF VARCHAR2 (5000) INDEX BY BINARY_INTEGER;

arrayPrimaryKeystmparray; --To save the analyse result of primary_Key_Column_names (暂存分析后得到的主键名)

arrayPrimaryKeyValuestmparray; --To save the analyse result of primary_key_values(暂存分析后得到的主键键值)

BEGIN

total_length :=0;

RES :='';

DECLARE

clobvarCLOB :=EMPTY_CLOB;

BEGIN

tmpPrimaryKeys :=primary_Key_Column_names;

tmpPrimaryKeyValues :=primary_key_values;

i :=0;

WHILE INSTR (tmpPrimaryKeys,'}') > 0

LOOP --Analyse the column names of primary key(将主键分开,相当于arrayPrimaryKeys =tmpPrimaryKeys.split("}") )

arrayPrimaryKeys (i) :=

SUBSTR (tmpPrimaryKeys,1,(INSTR (tmpPrimaryKeys,'}') - 1));

tmpPrimaryKeys :=

SUBSTR (tmpPrimaryKeys,(INSTR (tmpPrimaryKeys,'}') + 1));

i :=i + 1;

END LOOP;

i :=0;

WHILE INSTR (tmpPrimaryKeyValues,'}') > 0

LOOP--Analyse the values of primary key

arrayPrimaryKeyValues (i) :=

SUBSTR (tmpPrimaryKeyValues,

1,

(INSTR (tmpPrimaryKeyValues,'}') - 1));

tmpPrimaryKeyValues :=

SUBSTR (tmpPrimaryKeyValues,

(INSTR (tmpPrimaryKeyValues,'}') + 1));

i :=i + 1;

END LOOP;

IF arrayPrimaryKeys.COUNT () <> arrayPrimaryKeyValues.COUNT ()

THEN--判断键与键值是否能匹配起来

res :='KEY-VALUE NOT MATCH';

RETURN;

END IF;

i :=0;

sqlCon :='';

WHILE i <arrayPrimaryKeys.COUNT ()

LOOP

sqlCon :=

sqlCon

|| ' AND '

|| arrayPrimaryKeys (i)

|| '='''

|| REPLACE (arrayPrimaryKeyValues (i),'''','''''')

|| '''';

i :=i + 1;

END LOOP;

sqlStr :=

'SELECT '

|| clob_column_name

|| ' FROM '

|| table_name

|| ' WHERE 1=1 '

|| sqlCon

|| ' AND ROWNUM =1';--组查询字符串

DBMS_LOB.createtemporary (clobvar,TRUE);

DBMS_LOB.OPEN (clobvar,DBMS_LOB.lob_readwrite);

EXECUTE IMMEDIATE TRIM (sqlStr) INTO clobvar; --执行查询

IF offset_i <=1

THEN

total_length :=DBMS_LOB.getlength (clobvar);

END IF;

IF read_length_i <=0

THEN

tmpReadLength :=4000;

ELSE

tmpReadLength :=read_length_i;

END IF;

DBMS_LOB.READ (clobvar,

tmpReadLength,

offset_i,

res); --读取数据

IF DBMS_LOB.ISOPEN (clobvar) =1

THEN

DBMS_LOB.CLOSE (clobvar);

END IF;

END;

EXCEPTION

WHEN OTHERS

THEN

res :='';

total_length :=0;

END;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: