oracle數值類型--LONG類型

Oracle中的LONG類型有兩種:
LONG文本類型,能存儲2GB的文本。與VARCHAR2或CHAR類型同樣,存儲在LONG類型中的文本要進行字符集轉換。
LONG RAW類型,能存儲2GB的原始二進制數據(不用進行字符集轉換的數據)。
在此並不解釋如何使用LONG類型,而是會解釋爲何你不但願在應用中使用LONG(或LONG RAW)類型。首先要注意的是,Oracle文檔在如何處理LONG類型方面描述得很明確。Oracle SQL Reference手冊指出:
不要建立帶LONG列的表,而應該使用LOB列(CLOB、NCLOB、BLOB)。支持LONG列只是爲了保證向後兼容性。sql

1 LONG和LONG RAW類型的限制

 

LONG/LONG RAW類型                                         CLOB/BLOB類型
每一個表中只能有一個LONG或LONG RAW列         每一個表能夠有最多12.000個CLOB或BLOB類型的列
定義用戶定義的類型時,不能有LONG/LONG     用戶定義的類型完成可使用CLOB和BLOB類型
RAW類型的屬性
不能在WHERE子句中引用LONG類型                 WHERE子句中能夠引用LOB類型,並且DBMS_LOB包
                                                                        中提供了大量函數來處理LOB類型
除了NOT NULL以外,完整性約束中不能引用     完整性約束中能夠引用LOB類型
LONG類型
LONG類型不支持分佈式事務                                 LOB確實支持分佈式事務
LONG類型不能使用基本或高級複製技術來複制     LOB徹底支持複製
LONG列不能在GROUP BY、ORDER BY或             只要對LOB應用一個函數,將其轉換爲一個標量SQL類型,數據庫

CONNECT BY子句中引用,也不能在使用了         如VARCHAR二、NUMBER或DATE,LOB就能夠出如今
DISTINCT、UNIQUE、INTERSECT、MINUS     這些子句中
或UNION的查詢中使用
PL/SQL函數/過程不能接受LONG類型的輸入         PL/SQL能夠充分處理LOB類型
SQL內置函數不能應用於LONG列(如SUBSTR)     SQL函數能夠應用於LOB類型
CREATE TABLE AS SELECT語句中不能使用             LOB支持CREATE TABLE AS SELECT
LONG類型
在包含LONG類型的表上不能使用ALTER TABLE MOVE         能夠移動包含LOB的表安全

若是表中有一個LONG列,那麼不少事情都不能作。對於全部新的應用,甚至根本不應考慮使用LONG類型。相反,應該使用適當的LOB類型。對於現有的應用,若是受到表12.-2所列的某個限制,就應該認真地考慮將LONG類型轉換爲相應的LOB類型。因爲已經作了充分考慮來提供向後兼容性,因此編寫爲使用LONG類型的應用也能透明地使用LOB類型。app

 

2 處理遺留的LONG類型

「那如何考慮Oracle中的數據字典呢?「數據字典中散佈着LONG列,這就使得字典列的使用很成問題。例如,不能使用SQL搜索ALL_VIEWS字典視圖來找出包含文本HELLO的全部視圖:分佈式

scott@ORCL>select *
  2  from all_views
  3  where text like '%HELLO%';
where text like '%HELLO%'
      *
第 3 行出現錯誤:
ORA-00932: 數據類型不一致: 應爲 NUMBER, 但卻得到 LONG

這個問題並不僅是ALL_VIEWS視圖纔有,許多視圖都存在一樣的問題:函數

scott@ORCL>select table_name, column_name
  2  from dba_tab_columns
  3  where data_type in ( 'LONG', 'LONG RAW' )
  4  and owner = 'SYS'
  5  and table_name like 'DBA%';

TABLE_NAME                                                   COLUMN_NAME
------------------------------------------------------------ -------------------
-----------------------------------------
DBA_ADVISOR_SQLPLANS                                         OTHER
DBA_ARGUMENTS                                                DEFAULT_VALUE
DBA_CLUSTER_HASH_EXPRESSIONS                                 HASH_EXPRESSION
DBA_CONSTRAINTS                                              SEARCH_CONDITION
DBA_IND_EXPRESSIONS                                          COLUMN_EXPRESSION
DBA_IND_PARTITIONS                                           HIGH_VALUE
DBA_IND_SUBPARTITIONS                                        HIGH_VALUE
DBA_MVIEWS                                                   QUERY
DBA_MVIEW_AGGREGATES                                         MEASURE
DBA_MVIEW_ANALYSIS                                           QUERY
DBA_NESTED_TABLE_COLS                                        DATA_DEFAULT
DBA_OUTLINES                                                 SQL_TEXT
DBA_REGISTERED_MVIEWS                                        QUERY_TXT
DBA_REGISTERED_SNAPSHOTS                                     QUERY_TXT
DBA_SNAPSHOTS                                                QUERY
DBA_SQLSET_PLANS                                             OTHER
DBA_SQLTUNE_PLANS                                            OTHER
DBA_SUBPARTITION_TEMPLATES                                   HIGH_BOUND
DBA_SUMMARIES                                                QUERY
DBA_SUMMARY_AGGREGATES                                       MEASURE
DBA_TAB_COLS                                                 DATA_DEFAULT
DBA_TAB_COLUMNS                                              DATA_DEFAULT
DBA_TAB_PARTITIONS                                           HIGH_VALUE
DBA_TAB_SUBPARTITIONS                                        HIGH_VALUE
DBA_TRIGGERS                                                 TRIGGER_BODY
DBA_VIEWS                                                    TEXT
DBA_VIEWS_AE                                                 TEXT

已選擇27行。

若是你想在SQL中使用這些列,就須要將它們轉換爲一種對SQL友好的類型。可使用一個用戶定義的函數來作到這一點。如下例子展現瞭如何使用一個LONG SUBSTR函數來達到這個目的,這個函數容許將任何4,000字節的LONG類型轉換爲一個VARCHAR2,以便用於SQL。完成後,就能執行如下查詢。首先 如何獲得一個LONG類型的子串:fetch

scott@ORCL>create or replace package long_help
  2  authid current_user
  3  as
  4  function substr_of
  5  ( p_query in varchar2,
  6  p_from in number,
  7  p_for in number,
  8  p_name1 in varchar2 default NULL,
  9  p_bind1 in varchar2 default NULL,
 10  p_name2 in varchar2 default NULL,
 11  p_bind2 in varchar2 default NULL,
 12  p_name3 in varchar2 default NULL,
 13  p_bind3 in varchar2 default NULL,
 14  p_name4 in varchar2 default NULL,
 15  p_bind4 in varchar2 default NULL )
 16  return varchar2;
 17  end;
 18  /

程序包已建立。

在第2行上 指定了AUTHID CURRENT_USER。 這使得這個包會做爲調用者運行,擁有全部角色和權限。這一點很重要,緣由有兩個。首先,咱們但願數據庫安全性不要受到破壞,這個包只返回容許咱們(調用 者)看到的列子串。其次,咱們但願只在數據庫中將這個包安裝一次,就能一直使用它的功能;使用調用者權限能夠保證這一點。若是咱們使用PL/SQL的默認安全模型(定義者權限,define right),這個包會以全部者的權限來運行,這樣一來,它就只能看到包全部者能看到的數據,這可能不包括容許調用者看到的數據集。spa

函數SUBSTR_OF的基本思想是取一個查詢,這個查詢最多隻選擇一行和一列:即咱們感興趣的LONG值。若是須要,SUBSTR_OF會解析這個查詢,爲之綁定輸入,並經過查詢獲取結果,返回LONG值中必要的部分。
包體(實現)最前面聲明瞭兩個全局變量。G_CURSOR變量保證一個持久遊標在會話期間一直打開。這是爲了不反覆打開和關閉遊標,並避免沒必要要地過多解析SQL。第二個全局變量G_QUERY用於記住這個包中已解析的上一個SQL查詢的文本。只要查詢保持不變,就只需將其解析一次。所以,即便一個查詢中查詢了5,000行,只要咱們傳入這個函數的SQL查詢不變,就只會有一個解析調用:code

scott@ORCL>create or replace package body long_help
  2  as
  3
  4  g_cursor number := dbms_sql.open_cursor;
  5  g_query varchar2(32765);
  6
  7  procedure bind_variable( p_name in varchar2, p_value in varchar2 )
  8
  9  is
 10  begin
 11     if ( p_name is not null )
 12     then
 13             dbms_sql.bind_variable( g_cursor, p_name, p_value );
 14     end if;
 15  end;
 16
 17  function substr_of
 18  ( p_query in varchar2,
 19     p_from in number,
 20     p_for in number,
 21     p_name1 in varchar2 default NULL,
 22     p_bind1 in varchar2 default NULL,
 23     p_name2 in varchar2 default NULL,
 24     p_bind2 in varchar2 default NULL,
 25     p_name3 in varchar2 default NULL,
 26     p_bind3 in varchar2 default NULL,
 27     p_name4 in varchar2 default NULL,
 28     p_bind4 in varchar2 default NULL )
 29  return varchar2
 30
 31  as
 32     l_buffer varchar2(4000);
 33     l_buffer_len number;
 34
 35  begin
 36             if ( nvl(p_from,0) <= 0 )
 37             then
 38                     raise_application_error
 39                     (-20002, 'From must be >= 1 (positive numbers)' );
 40             end if;
 41
 42             if ( nvl(p_for,0) not between 12 and 4000 )
 43             then
 44                     raise_application_error
 45                     (-20003, 'For must be between 12 and 4000' );
 46             end if;
 47
 48             if ( p_query <> g_query or g_query is NULL )
 49             then
 50                     if ( upper(trim(nvl(p_query,'x'))) not like 'SELECT%')
 51                     then
 52                             raise_application_error
 53                             (-20001, 'This must be a select only' );
 54                     end if;
 55                     dbms_sql.parse( g_cursor, p_query, dbms_sql.native );
 56                     g_query := p_query;
 57             end if;
 58
 59             bind_variable( p_name1, p_bind1 );
 60             bind_variable( p_name2, p_bind2 );
 61             bind_variable( p_name3, p_bind3 );
 62             bind_variable( p_name4, p_bind4 );
 63
 64             dbms_sql.define_column_long(g_cursor, 1);
 65             if (dbms_sql.execute_and_fetch(g_cursor)>0)
 66             then
 67                     dbms_sql.column_value_long
 68                     (g_cursor, 1, p_for, p_from-1,
 69                     l_buffer, l_buffer_len );
 70             end if;
 71     return l_buffer;
 72  end substr_of;
 73
 74  end;
 75  /

程序包體已建立。
scott@ORCL>select *
  2  from (
  3     select owner, view_name,
  4             long_help.substr_of( 'select text
  5             from dba_views
  6             where owner = :owner
  7             and view_name = :view_name',
  8             1, 4000,
  9             'owner', owner,
 10             'view_name', view_name ) substr_of_view_text
 11     from dba_views
 12     where owner = user
 13  )
 14  where upper(substr_of_view_text) like '%INNER%'
 15  /

未選定行
scott@ORCL>select *
  2  from (
  3     select table_owner, table_name, partition_name,
  4             long_help.substr_of
  5                     ( 'select high_value from all_tab_partitions
  6                     where table_owner = :o and table_name = :n and partition
_name = :p',
  7             1, 4000,
  8             'o', table_owner,
  9             'n', table_name,
 10             'p', partition_name ) high_value
 11     from all_tab_partitions
 12     where table_name = 'T'
 13     and table_owner = user
 14  )
 15  where high_value like '%2003%'
 16  /

未選定行

還有一種方法,可使用TO_LOB內置函數和一個全局臨時表,將LONG或LONG RAW臨時地轉換爲CLOB或BLOB。爲此,PL/SQL過程能夠以下:事務

Insert into global_temp_table ( blob_column )
select to_lob(long_raw_column) from t where...

這在偶爾須要處理單個LONG RAW值的應用中能很好地工做。不過,爲此須要作的工做太多了。應該乾脆將LONG RAW一次性轉換爲BLOB,而後處理BLOB。

相關文章
相關標籤/搜索