分享

Oracle 外部表

 cinnamon 2011-10-12

   外部表只能在Oracle 9i之后来使用。简单地说,外部表,是指不存在于数据库中的表。通过向Oracle提供描述外部表的元数据,我们

可以把一个操作系统文件当成一个只读的数据库表,就像这些数据存储在一个普通数据库表中一样来进行访问。外部表是对数据库表的延伸。

 

一、外部表的特性

   位于文件系统之中,按一定格式分割,如文本文件或者其他类型的表可以作为外部表。

   对外部表的访问可以通过SQL语句来完成,而不需要先将外部表中的数据装载进数据库中。

   外部数据表都是只读的,因此在外部表不能够执行DML操作,也不能创建索引。

   ANALYZE语句不支持采集外部表的统计数据,应该使用DMBS_STATS包来采集外部表的统计数据。

 

二、创建外部表的注意事项

   1.需要先建立目录对象

 

   2.对于操作系统文件的要求

       文件要有固定的格式、不能有标题列、访问时会自动创建一个日志文件

 

   3.在建立临时表时的相关限制

       对表中字段的名称存在特殊字符的情况下,必须使用英文状态的下的双引号将该表列名称连接起来。如采用”SalseID#”。

       对于列名字中特殊符号未采用双引号括起来时,会导致无法正常查询数据。

       建议不用使用特殊的列标题字符

 

       在创建外部表的时候,并没有在数据库中创建表,也不会为外部表分配任何的存储空间。

       创建外部表只是在数据字典中创建了外部表的元数据,以便对应访问外部表中的数据,而不在数据库中存储外部表的数据。

       简单地说,数据库存储的只是与外部文件的一种对应关系,如字段与字段的对应关系。而没有存储实际的数据。

       由于存储实际数据,故无法为外部表创建索引,同时在数据使用DML时也不支持对外部表的插入、更新、删除等操作。

 

   4.删除外部表或者目录对象

       一般情况下,先删除外部表,然后再删除目录对象,如果目录对象中有多个表,应删除所有表之后再删除目录对象。

       如果在未删除外部表的情况下,强制删除了目录,在查询到被删除的外部表时,将收到"对象不存在"的错误信息。

       查询dba_external_locations来获得当前所有的目录对象以及相关的外部表,同时会给出这些外部表所对应的操作系统文件的名字。

           

   5.对于操作系统平台的限制

       不同的操作系统对于外部表有不同的解释和显示方式

       如在Linux操作系统中创建的文件是分号分隔且每行一条记录,但该文件在Windows操作系统上打开则并非如此。

       建议避免不同操作系统以及不同字符集所带来的影响

 

三、创建外部表

   使用CREATE TABLE语句的ORGANIZATION EXTENERAL子句来创建外部表。外部表不分配任何盘区,因为仅仅是在数据字典中创建元数据。

   1.外部表的创建语法

       createtabletable_name

           (col1 datatype1,col2 datatype2,col3 datatype3)

            organization exteneral

           (.....)

           

   2.由查询结果集,使用Oracle_datapump来填充数据来生成外部表

       a.创建系统目录以及Oracle数据目录名来建立对应关系,同时授予权限

           [oracle@oradb ~]$ mkdir-p/home/oracle/external_tb/data

       

           sys@ORCL>createorreplacedirectory dat_diras'/home/oracle/external_tb/data/';

 

           sys@ORCL>grantread,writeondirectory dat_dirtoscott;

 

       b.创建外部表

 

           scott@ORCL>createtableex_tb1  --创建外部表

            2 (ename,job,sal,dname)       --表列描述,注意未指定数据类型

            3 organizationexternal

            4 (

            5   typeoracle_datapump      --使用datapump将查询结果填充到外部表,注,此处由select生成,故不支持oracle_loader

            6   defaultdirectory dat_dir --指定外部表的存放目录

            7   location('tb1.exp','tb2.exp') --产生外部表的内容将填充到这些文件中

            8 )

            9   parallel                      --按并行方式来填充

            10 as

           11   selectename,job,sal,dname    -填充使用的原始数据

            12   fromempjoindept

            13     onemp.deptno=dept.deptno;

 

       c.--验证外部表

           scott@ORCL>select*fromex_tb1;

 

           ENAME     JOB             SAL DNAME

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

           SMITH     CLERK           800 RESEARCH

           ALLEN     SALESMAN       1600 SALES

           WARD      SALESMAN       1250 SALES

           JONES     MANAGER        2975 RESEARCH

                   ..........

       

           对于使用上述方式创建的外部表可以将其复制到其他路径作为外部表的原始数据来生成新的外部表,用于转移数据。

           

   3.使用SQLLDR提供外部表的定义并创建外部表

       关于SQL*Loader的使用请参照:SQL*Loader使用方法

       我们使用SQL*Loader和下面的这个控制文件来生成外部表的定义

           [oracle@oradb ~]$ cat demo1.ctl

           LOADDATA

           INFILE*

           INTOTABLEDEPT_NEW

           FIELDS TERMINATEDBY','

           (DEPTNO,DNAME,LOC)

           BEGINDATA

           10,Sales,Virginia

           20,Accounting,Virginia

           30,Consulting,Virginia

           40,Finance,Virginia

                       

           [oracle@oradb ~]$ sqlldr scott/tiger control=demo1.ctl external_table=generate_only

 

       EXTERNAL_TABLE参数有以下三个值:

           NOT_USED:默认值。

           EXECUTE:这个值说明SQLLDR不会生成并执行一个SQLINSERT语句;而是会创建一个外部表,且使用一个批量SQL语句来加载。

           GENERATE_ONLY:使SQLLDR并不具体加载任何数据,而只是会生成所执行的SQL DDL和DML语句,并放到它创建的日志文件中。

   

       注:DIRECT=TRUE覆盖EXTENAL_TABLE=GENERATE_ONLY。如果指定了DIRECT=TRUE,则会加载数据,而不会生成外部表。

 

       [oracle@oradb ~]$ cat demo1.log   --查看sqlldr产生的日志文件

 

       TableDEPT_NEW,loadedfromevery logical record.

       Insertoptionineffectforthistable:INSERT

 

         ColumnName                 Position  Len Term Encl Datatype

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

       DEPTNO                             FIRST    *  ,      CHARACTER           

       DNAME                               NEXT    *  ,      CHARACTER           

       LOC                                 NEXT    *  ,      CHARACTER           

 

       CREATEDIRECTORY statements neededforfiles  --创建一个目录

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

       CREATEDIRECTORY SYS_SQLLDR_XT_TMPDIR_00000AS'/home/oracle/'

 

       CREATETABLEstatementforexternaltable:    --生成创建外部表的命令

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

       CREATETABLE"SYS_SQLLDR_X_EXT_DEPT_NEW"

       (

        "DEPTNO" NUMBER(2),

        "DNAME" VARCHAR2(20),

        "LOC" VARCHAR2(20)

       )

       ORGANIZATIONexternal                --该子句表明是一个外部表heap对应普通表,index对应iot,external对应外部表

       (

        TYPEoracle_loader                 --说明外部文件访问方式:oracle_loader或oracle_datapump(9i不支持)

        DEFAULTDIRECTORY SYS_SQLLDR_XT_TMPDIR_00000  --指定外部文件的缺省目录

        ACCESS PARAMETERS                             --这个访问参数有些类似于sqlldr中控制文件中的描述信息

        (                                            --系统根据这些描述信息来生成外部表的格式

           RECORDS DELIMITEDBYNEWLINE CHARACTERSET US7ASCII   --记录默认以换行符结束

           BADFILE'SYS_SQLLDR_XT_TMPDIR_00000':'demo1.bad'     --存放处理失败的记录文件描述

           LOGFILE'demo1.log_xt'                               --日志文件

           READSIZE 1048576--Oracle读取输入数据文件所用的默认缓冲区,此处为MB,如专用模式则从PGA分配,如共享模式则从SGA分配

           SKIP 6                                      --跳过的记录数,因为我们使用了控制文件,所以前面的控制信息需要跳过

           FIELDS TERMINATEDBY"," LDRTRIM            --描述字段的终止符

           REJECT ROWSWITHALLNULLFIELDS            --所有为空值的行被跳过并且记录到bad file.

           (                                           --下面是描述外部文件各个列的定义

            "DEPTNO"CHAR(255)

               TERMINATEDBY",",

            "DNAME"CHAR(255)

               TERMINATEDBY",",

            "LOC"CHAR(255)

               TERMINATEDBY","

           )

        )

        location

        (

           'demo1.ctl'                               --描述外部文件的文件名

        )

       )REJECT LIMIT UNLIMITED                       --描述允许的错误数,此处为无限制

 

       INSERTstatements usedtoloadinternal tables:            --用于将数据填充到表,使用append方式

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

       INSERT/*+ append */INTODEPT_NEW

       (

        DEPTNO,

        DNAME,

        LOC

       )

       SELECT

        "DEPTNO",

        "DNAME",

        "LOC"

       FROM"SYS_SQLLDR_X_EXT_DEPT"

 

       statementstocleanup objects createdbyprevious statements:   --用于删除目录和外部表的定义信息

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

       DROPTABLE"SYS_SQLLDR_X_EXT_DEPT_NEW"

       DROPDIRECTORY SYS_SQLLDR_XT_TMPDIR_00000

 

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

       sys@ORCL>grantcreateanydirectorytoscott;

 

       sys@ORCL>grantdropanydirectorytoscott;

 

       scott@ORCL>createtabledept_new

        2 (deptno number,dname varchar2(20),loc varchar2(25));

 

       scott@ORCL>select*fromdept_new;

 

       norows selected

       

       [oracle@oradb ~]$ sqlldr scott/tiger control=demo1.ctl external_table=execute

 

       scott@ORCL>select*fromdept_new;

 

           DEPTNO DNAME               LOC

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

               10 Sales               Virginia

               20 Accounting          Virginia

               30 Consulting          Virginia

               40 Finance             Virginia

 

   4.使用平面文件定义并生成外部表

       a.平面文件数据

           1.dat

               7369,SMITH,CLERK,7902,17-DEC-80,100,0,20

               7499,ALLEN,SALESMAN,7698,20-FEB-81,250,0,30

               7521,WARD,SALESMAN,7698,22-FEB-81,450,0,30

               7566,JONES,MANAGER,7839,02-APR-81,1150,0,20

 

           2.dat

               7654,MARTIN,SALESMAN,7698,28-SEP-81,1250,0,30

               7698,BLAKE,MANAGER,7839,01-MAY-81,1550,0,30

               7934,MILLER,CLERK,7782,23-JAN-82,3500,0,10

 

       b.继续使用前面创建的目录/home/oracle/external_tb/data来存放数据文件:

 

          sys@ORCL>select*fromdba_directories;

 

           OWNER          DIRECTORY_NAME DIRECTORY_PATH

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

           SYS            DATA_PUMP_DIR  /u01/oracle/10g/rdbms/log/

           SYS            DAT_DIR        /home/oracle/external_tb/data/

           

           scott@ORCL>ho ls/home/oracle/external_tb/data/

           1.dat 2.dat tb1.exp tb2.exp

           

       c.创建外部表

           scott@ORCL>get/u01/bk/scripts/tb.emp_new

            1 createtableemp_new

            2 (

            3     emp_id number(4),

            4     ename varchar2(15),

            5     job varchar2(12),

            6     mgr_id number(4),

            7     hiredate date,

            8     salary number(8),

            9     comm number(8),

            10     dept_id number(2)

            11 )

            12 organizationexternal

            13 (

            14     typeoracle_loader

            15     defaultdirectory dat_dir

            16     access parameters

            17   (

            18       records delimitedbynewline

            19       fields terminatedby','

            20   )

            21 location

            22     ('1.dat','2.dat')

            23*);

            

            scott@ORCL>start/u01/bk/scripts/tb.emp_new

 

       d.验证外部表  

           scott@ORCL>select*fromemp_new;

 

               EMP_ID ENAME          JOB             MGR_ID HIREDATE     SALARY      COMM   DEPT_ID

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

                7369 SMITH          CLERK             7902 17-DEC-80       100         0        20

                7499 ALLEN          SALESMAN          7698 20-FEB-81       250         0        30

                                   ............................

               

           scott@ORCL>deletefromemp_newwhereename='SMITH';  --外部表不能执行DML

           deletefromemp_newwhereename='SMITH'

                       *

           ERROR at line 1:

           ORA-30657:operationnotsupportedonexternalorganizedtable

           

           scott@ORCL>insertintoemp_new(emp_id,ename)select8888,'Robinson'fromdual;

           insertintoemp_new(emp_id,ename)select8888,'Robinson'fromdual

                       *

           ERROR at line 1:

           ORA-30657:operationnotsupportedonexternalorganizedtable

                                       

     e.获得外部表的有关信息:

           scott@ORCL>col access_parameters format a35

           scott@ORCL>selectowner,table_name,type_name,default_directory_name,access_parameters

            2 fromdba_external_tables;

 

           OWNER     TABLE_NAME     TYPE_NAME                     DEFAULT_DIRECTO ACCESS_PARAMETERS

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

           SCOTT     EX_TB1         ORACLE_DATAPUMP               DAT_DIR

           SCOTT     EMP_NEW        ORACLE_LOADER                 DAT_DIR        records delimitedbynewline

                                                                                           fields terminatedby','

 

 

           SCOTT     EMP_PUMP       ORACLE_DATAPUMP               DAT_DIR        records delimitedbynewline

                                                                                           fields terminatedby','

  

     f.获得平面文件的位置,使用如下的查询:

           scott@ORCL>select*fromdba_external_locationsorderbytable_name;

 

           OWNER     TABLE_NAME     LOCATION       DIR DIRECTORY_NAME

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

           SCOTT     EMP_NEW        1.dat          SYS DAT_DIR

           SCOTT     EMP_NEW        2.dat          SYS DAT_DIR

           SCOTT     EMP_PUMP       1.dat          SYS DAT_DIR

           SCOTT     EMP_PUMP       2.dat          SYS DAT_DIR

           SCOTT     EX_TB1         tb2.exp        SYS DAT_DIR

           SCOTT     EX_TB1         tb1.exp        SYS DAT_DIR     

               

   5.外部表定义的进一步分析

       CREATETABLEexternal_table

        (

           COL01 VARCHAR2(100),

               COL02 NUMBER,

                ......

        )

       ORGANIZATIONEXTERNAL

       (

           TYPEORACLE_LOADER

           DEFAULTDIRECTORY "XXX"

           ACCESS PARAMETERS

               (

               RECORDS DELIMITEDBY0X'0A'

               SKIP 1

               BADFILE'bad.txt'

               FIELDS TERMINATEDBY','

               OPTIONALLY ENCLOSEDBY'"'

               LRTRIM MISSING FIELDVALUESARENULL

               REJECT ROWSWITHALLNULLFIELDS

               )

           LOCATION

               ("CJ_DIR":'data.txt')

       )REJECT LIMIT UNLIMITED;

 

       外部表定义的几个重点

           a.ORGANIZATIONEXTERNAL关键字,必须要有。以表明定义的表为外部表。

           b.重要参数外部表的类型

               ORACLE_LOADER:定义外部表的缺省方式,只能只读方式实现文本数据的装载。

               ORACLE_DATAPUMP:支持对数据的装载与卸载,数据文件必须为二进制dump文件。可以从外部表提取数据装载到内部表,也

                   可以从内部表卸载数据作为二进制文件填充到外部表。

           c.DEFAULTDIRECTORY:缺省的目录指明了外部文件所在的路径

           d.LOCATION:定义了外部表的位置

           f.ACCESS PARAMETERS:描述如何对外部表进行访问

               RECORDS关键字后定义如何识别数据行  

                   DELIMITEDBY'XXX'——换行符,常用newline定义换行,并指明字符集。对于特殊的字符则需要单独定义,

                       如特殊符号,可以使用OX'十六位值',例如tab(/t)的十六位是9,则DELIMITEDBY0X'09'

                       cr(/r)的十六位是d,那么就是DELIMITEDBY0X'0D'

                   SKIP X ——跳过X行数据,有些文件中第一行是列名,需要跳过第一行,则使用SKIP 1

                   

               FIELDS关键字后定义如何识别字段,常用的如下:

                   FIELDS:TERMINATEDBY'x'——字段分割符。

                   ENCLOSEDBY'x'——字段引用符,包含在此符号内的数据都当成一个字段。

                   例如一行数据格式如:"abc","a""b,""c,"。使用参数TERMINATEDBY','ENCLOSEDBY'"'后,系统会读到两个字段,

                       第一个字段的值是abc,第二个字段值是a"b,"c,

                   LRTRIM ——删除首尾空白字符。

                   MISSING FIELDVALUESARENULL——某些字段空缺值都设为NULL

 

                   对于字段长度和分割符不确定且准备用作外部表文件,可以使用UltraEdit、Editplus等来进行分析测试,如果文件较

                   大,则需要考虑将文件分割成小文件并从中提取数据进行测试。

       

       外部表对错误的处理

           REJECT LIMIT UNLIMITED

               在创建外部表时最后加入LIMIT子句,表示可以允许错误的发生个数。默认值为零。设定为UNLIMITED则错误不受限制

           BADFILE和NOBADFILE子句

               用于指定将捕获到的转换错误存放到哪个文件。如果指定了NOBADFILE则表示忽略转换期间的错误

               如果未指定该参数,则系统自动在源目录下生成与外部表同名的.BAD文件

               BADFILE记录本次操作的结果,下次将会被覆盖

           LOGFILE和NOLOGFILE子句

               同样在accessparameters中加入LOGFILE'LOG_FILE.log'子句,则所有Oracle的错误信息放入'LOG_FILE.log'

              而NOLOGFILE子句则表示不记录错误信息到log中,如忽略该子句,系统自动在源目录下生成与外部表同名的.LOG文件

 

       注意以下几个常见的问题

           1.外部表经常遇到BUFFER不足的情况,因此尽可能的增大READSIZE

           2.换行符不对产生的问题。在不同的操作系统中换行符的表示方法不一样,碰到错误日志提示如是换行符问题,可以使用

               UltraEdit打开,直接看十六进制

           3.特定行报错时,查看带有"BAD"的日志文件,其中保存了出错的数据,用记事本打开看看那里出错,是否存在于外部表定义相冲突


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多