2008年9月30日 星期二

Dynamic SQL and Global Variable using DB2 9


/*
  Purpose: 使用 Global Variable 提升 Dynamic SQL 的 performance
  建立兩個不同的 procedures 比較使用或不使用 Global Variable 的效能差異

  參考: Expert One-on-One (Thomas Kyte) 
     topic〔Use Bind Variables〕
*/


/* Connect to ORIONDB */

C:\>db2 connect to oriondb

  資料庫連線資訊

 資料庫伺服器     = DB2/NT 9.5.0
 SQL 授權 ID     = ORION
 本地資料庫別名    = ORIONDB

/* Create Globa Variable */

C:\>db2 create variable orion.keyvalue integer
DB20000I SQL 指令已順利完成。

/* 建立測試 Table Target_tab */

create table target_tab
(
  col1 integer,
  col2 varchar(64),
  col3 varchar(64)
) in userspace1

/* 建立測試 Table Source_tab */

create table source_tab
(
  col1 integer,
  col2 varchar(64),
  col3 varchar(64)
) in userspace1

/* 新增測試資料 */

insert into source_tab
select row_number() over(),tbname,name
from sysibm.syscolumns;

insert into source_tab
select (select max(col1) + 1 from source_tab),
    tbname,name
from  sysibm.syscolumns;

insert into source_tab
select (select max(col1) + 1 from source_tab),
    tbname,name
from  sysibm.syscolumns;

insert into source_tab
select (select max(col1) + 1 from source_tab),
    tbname,name
from  sysibm.syscolumns;

select count(*) from source_tab

1
-----------
   19804

  已選取 1 個記錄。


/*
  Create Procedure sp_testvariable (使用 Global Variable:KeyValue)
*/


CREATE PROCEDURE SP_TESTVARIABLE
SPECIFIC SP_TESTVARIABLE
LANGUAGE SQL
BEGIN
    DECLARE n INTEGER;
    DECLARE i INTEGER;
    DECLARE strSql VARCHAR(128);

    SELECT COUNT(*) INTO n
    FROM  SOURCE_TAB;

    SET i = 1;
    WHILE i <= n DO
        -- 使用剛才建立的 Global Variable
        SET KeyValue = i;
        SET strSql = 'INSERT INTO TARGET_TAB ' ||
               'SELECT * FROM SOURCE_TAB ' ||
               'WHERE COL1 = KeyValue';
        EXECUTE IMMEDIATE strSqL;
        SET i = i + 1;
    END WHILE;
END


/*
  Create Procedure sp_testnovariable (不使用 Global Variable)
*/


CREATE PROCEDURE SP_TESTNOVARIABLE
SPECIFIC SP_TESTNOVARIABLE
LANGUAGE SQL
BEGIN
    DECLARE n INTEGER;
    DECLARE i INTEGER;
    DECLARE strSql VARCHAR(128);

    SELECT COUNT(*) INTO n
    FROM  SOURCE_TAB;

    SET i = 1;
    WHILE i <= n DO
        SET strSql = 'INSERT INTO TARGET_TAB ' ||
               'SELECT * FROM SOURCE_TAB ' ||
               'WHERE COL1 = ' || CHAR(i);
        EXECUTE IMMEDIATE strSqL;
        SET i = i + 1;
    END WHILE;
END

/* 編寫 CLP Script: test.sql 內容如下 */

alter table target_tab activate not logged initially with empty table;

values current timestamp;

call sp_testvariable;

values current timestamp;

/* 編寫 CLP Script: testno.sql 內容如下 */

alter table target_tab activate not logged initially with empty table;

values current timestamp;

call sp_testnovariable;

values current timestamp;

/* 執行 test.sql (使用Global Variable) */

C:\>db2 -tf test.sql
DB20000I SQL 指令已順利完成。

1
--------------------------
2008-10-01-14.12.39.334000

  已選取 1 個記錄。

 傳回狀態 = 0

1
--------------------------
2008-10-01-14.13.55.324000

  已選取 1 個記錄。

C:\>db2 select count(*) from target_tab

1
-----------
   19804

  已選取 1 個記錄。

/* 計算執行時間(秒) */

SELECT TIMESTAMPDIFF(2,CHAR(TIMESTAMP('2008-10-01-14.13.55.324000')-
                 TIMESTAMP('2008-10-01-14.12.39.334000'))) SEC
FROM SYSIBM.SYSDUMMY1

SEC
-------------
75
  已選取 1 個記錄。

/* 執行 testno.sql(不使用Global Variable) */

C:\>db2 -tf testno.sql
DB20000I SQL 指令已順利完成。

1
--------------------------
2008-10-01-14.14.29.964000

  已選取 1 個記錄。

 傳回狀態 = 0

1
--------------------------
2008-10-01-14.16.50.446000

  已選取 1 個記錄。

/* 計算執行時間(秒) */

SELECT TIMESTAMPDIFF(2,CHAR(TIMESTAMP('2008-10-01-14.16.50.446000')-
                 TIMESTAMP('2008-10-01-14.14.29.964000'))) SEC
FROM SYSIBM.SYSDUMMY1

SEC
--------------
140

已選取 1 個記錄。

/* 不使用Global Variable 的 Dynamic SQL 執行效率慢了將近一倍的時間 */

Heterogeneous Services with different characterset using Oracle10g


/*
  1) connect DB2 using Generic Connectivity
     - odbc configuration
     - change parameter HS_FDS_CONNECT_INFO and make .ora file
     - SQLNet.ora,tnsname.ora,listener.ora
     - create database link
  2) query DB2 (big5) testing table
*/

/* 1) connect DB2 using Generic Connectivity */

/*
  -- 設定 odbc
  資料庫來源名稱: CDIDB
  資料庫別名: CDIDB88
*/





/*
  從 C:\oracle\product\10.2.0\db_1\hs\admin下
  複製 inithsodbc.ora 命名格式 init + DSN Name + .ora
  => initCDIDB88.ora
*/



/*開啟 initCDIDB88.ora 設定參數 HS_FDS_CONNECT_INFO */

HS_FDS_CONNECT_INFO = CDIDB88

/* 開啟 SQLNet.ora 做以下變更 */

SQLNET.AUTHENTICATION_SERVICES= (NTS)

/* 開啟 tnsname.ora 增加以下設定 */

CDIDB88 =
 (DESCRIPTION =
  (ADDRESS_LIST =
    (ADDRESS = (PROTOCOL = TCP)(HOST = ODDYSEY)(PORT = 1521))
   )
  (CONNECT_DATA =
    (SID = CDIDB88)
  )
  (HS = OK)
 )

/* 開啟 listener.ora 增加以下設定 */
 
(SID_DESC =
   (PROGRAM = hsodbc)
   (ORACLE_HOME = c:\oracle\product\10.2.0\db_1)
   (SID_NAME = CDIDB88)
)

/* Listener stop & start */

lsnrctl stop

lsnrctl start

/* connect / as sysdba */

/* create database link */

create database link db2svr
connect to “db2admin”
identified by “db2admin”
using 'CDIDB88';

/* Oracle DB 字元集 */

SQL> select value from nls_database_parameters
2  where parameter = 'NLS_CHARACTERSET';

VALUE
---------------
AL32UTF8


/* Back to CDIDB88 */

C:\>db2 get db config for cdidb88

    資料庫 cdidb88 的資料庫配置
 
 資料庫配置版次           = 0x0a00
 資料庫版次             = 0x0a00

 資料庫專屬區            = TW
 資料庫字碼頁            = 950
 資料庫字碼集            = big5
 資料庫國碼/地區碼         = 88
 資料庫對照順序           = UNIQUE
 替代對照順序     (ALT_COLLATE) =
 ‧
 ‧
 ‧

/* 建立測試 Table & 新增測試資料 */

C:\>db2 create table db2_big5_tab ( col1 varchar(6)) in userspace1
DB20000I SQL 指令已順利完成。

C:\>db2 insert into db2_big5_tab values ('一二三')
DB20000I SQL 指令已順利完成。

/* Back to ORACLE */
/* 透過 Database Link 看 db2 測試table layout */

SQL> desc db2_big5_tab@db2svr

 名稱          空值?       類型
 -------------------- --------------- ----------------
 COL1                   VARCHAR2(6)

/* Oracle 在 select 時不受自己 characterset 的影響,資料可完整顯示 */

SQL> select * from db2_big5_tab@db2svr;

COL1
---------
一二三

/* 新增時也可完整新增至 db2 table */

SQL> insert into db2_big5_tab@db2svr values ('四五六');

已建立 1 個資料列.

SQL> commit;

確認完成.

/* Back to DB2 */
/* 從 db2 看測試 table */

C:\>db2 select * from db2_big5_tab

COL1
------
一二三
四五六

  已選取 2 個記錄。

/* 重建測試 Table */

C:\>db2 drop table db2_big5_tab
DB20000I SQL 指令已順利完成。

C:\>db2 create table db2_big5_tab (col1 char(2)) in userspace1
DB20000I SQL 指令已順利完成。

C:\>db2 insert into db2_big5_tab values ('一')
DB20000I SQL 指令已順利完成。

/* 重新登錄 Oracle */

SQL> desc db2_big5_tab@db2svr
 
 名稱         空值?  類型
 ------------------ ------- ----------------
 COL1             CHAR(2)

/* 看一下內容與長度 */

SQL> select * from db2_big5_tab@db2svr;

COL1
------------


SQL> select lengthb(col1) from db2_big5_tab@db2svr;

LENGTHB(COL1)
-------------
       3

2008年9月25日 星期四

Federated UTF-8 and BIG5 databases using DB2 9


/*
  DATABASES:
        ORIONDB (codeset UTF-8)
        BIG5DB (codeset BIG5)
  TABLES:
        ORIONDB.UTF8_TAB
        BIG5DB.BIG5_TAB
  Create nickname UTF8_TAB on Database BIG5DB for ORIONDB.UTF8_TAB
  Create nickname BIG5_TAB on Database ORIONDB for BIG5DB.BIG5_TAB
  Insert multi-byte characters respectively
*/

/* check codeset on ORIONDB */

C:\>db2 get db cfg for oriondb

    資料庫 oriondb 的資料庫配置

 資料庫配置版次              = 0x0c00
 資料庫版次                = 0x0c00

 資料庫專屬區               = TW
 資料庫字碼頁               = 1208
 資料庫字碼集               = UTF-8
 資料庫國碼/地區碼            = 88
 資料庫對照順序              = IDENTITY
 ‧
 ‧
 ‧

/* Create Database BIG5DB */

create database big5db on 'c:\' using codeset BIG5 TERRITORY TW COLLATE using SYSTEM

C:\>db2 get db cfg for big5db

    資料庫 big5db 的資料庫配置

 資料庫配置版次              = 0x0c00
 資料庫版次                = 0x0c00

 資料庫專屬區               = TW
 資料庫字碼頁               = 950
 資料庫字碼集               = big5
 資料庫國碼/地區碼            = 88
 資料庫對照順序              = UNIQUE
 ‧
 ‧
 ‧

/* Connect to BIG5DB */

C:\>db2 connect to big5db

  資料庫連線資訊

 資料庫伺服器      = DB2/NT 9.5.0
 SQL 授權 ID      = ORION
 本地資料庫別名     = BIG5DB

/* Create Table BIG5_TAB on BIG5DB */

CREATE TABLE BIG5_TAB
(
  COL1 VARCHAR(10)
) IN USERSPACE1

INSERT INTO BIG5_TAB VALUES ('BIG-5')


/*
  Create Wrapper and Server on database BIG5DB for database ORIONDB
  to create nickname later.
  Server name: BIG5DB
*/

/* Connect to ORIONDB */

C:\>db2 connect to oriondb

  資料庫連線資訊

 資料庫伺服器      = DB2/NT 9.5.0
 SQL 授權 ID      = ORION
 本地資料庫別名     = ORIONDB

/* Create Table UTF8_TAB on ORIONDB */

CREATE TABLE UTF8_TAB
(
  COL1 VARCHAR(12)
) IN USERSPACE1

INSERT INTO UTF8_TAB VALUES ('UTF8')

/* Create Nickname BIG5_TAB on ORIONDB */

C:\>db2 create nickname orion.big5_tab for big5db.orion.big5_tab
DB20000I SQL 指令已順利完成。


/*
  Back to BIG5DB
  Create Nickname UTF8_TAB on BIG5DB
*/


C:\>db2 connect to big5db

  資料庫連線資訊

 資料庫伺服器      = DB2/NT 9.5.0
 SQL 授權 ID      = ORION
 本地資料庫別名     = BIG5DB

C:\>db2 create nickname orion.utf8_tab for oriondb.orion.utf8_tab
DB20000I SQL 指令已順利完成。

C:\>db2 select * from utf8_tab

COL1
------------
UTF8

  已選取 1 個記錄。

/* Check Nickname Layout */

C:\>db2 describe table utf8_tab

直欄名稱 綱目   資料類型名稱  長度  比例 Null
------- --------- ------------ ------ ---- ------
COL1  SYSIBM   VARCHAR     12   0  是

  已選取 1 個記錄。

/* Check Data using HEX */

C:\>db2 select hex(col1) from utf8_tab fetch first 1 row only

1
------------------------
EFBCB5EFBCB4EFBCA6EFBC98

  已選取 1 個記錄。

/* Check HEX Data which Database BIG5DB use exactly */

C:\>db2 select hex('一') from sysibm.sysdummy1

1
----
A440

  已選取 1 個記錄。

/* It would be failed as inserting more than four multi-byte characters */

C:\>db2 insert into utf8_tab values ('一二三四五')
DB21034E 指令被當作 SQL 陳述式處理,因為他不是有效的「指令行處理器」指令。 在SQL 處理程序期間,他已傳回:
SQL1822N 從資料來源 "ORIONDB" 接收到的非預期錯誤碼"22001"。相關的文字及記號為 "func="SQLExecute" msg=" SQL0433N 值 "一二三四五"太長。"。 SQLSTATE=560BD

C:\>db2 insert into utf8_tab values ('一二三四')
DB20000I SQL 指令已順利完成。

/* Back to Database ORIONDB */

C:\>db2 connect to oriondb

  資料庫連線資訊

 資料庫伺服器      = DB2/NT 9.5.0
 SQL 授權 ID      = ORION
 本地資料庫別名     = ORIONDB


/*
  two multi-byte characters are failed to select
  real value is 'BIG-5'
*/


C:\>db2 select * from big5_tab

COL1
----------
BIG

  已選取 1 個記錄。

/* Check Nickname Layout */

C:\>db2 describe table big5_tab

直欄名稱 綱目   資料類型名稱  長度  比例 Null
------- --------- ------------ ------ ---- ------
COL1  SYSIBM   VARCHAR     10   0  是

  已選取 1 個記錄。

/* You can insert precise length data, but fail to select completely */

C:\>db2 insert into big5_tab values ('一二三四五')
DB20000I SQL 指令已順利完成。

C:\>db2 select * from big5_tab

COL1
----------
BIG
一二三

  已選取 2 個記錄。

/* Check hex data from big5_tab */

C:\>db2 select hex(col1) from big5_tab fetch first 1 row only

1
------------------------------
A2D0A2D7A2D5A1D0A2B4

已選取 1 個記錄。

/* Check HEX Data which Database ORIONDB use exactly */

C:\>db2 select hex('一') from sysibm.sysdummy1

1
------
E4B880

已選取 1 個記錄。


/*
  Alter nickname big5_tab (length / 2 * 3)
  to show whole data
*/


C:\>db2 alter nickname orion.big5_tab alter column col1 local type varchar(15)
DB20000I SQL 指令已順利完成。

C:\>db2 select * from big5_tab

COL1
---------------
BIG-5
一二三四五

  已選取 2 個記錄。


/*
  after delete record where col1 = '一二三四五'
  I found something really odd:
  select with fetch or not will have very different result on hex
*/


C:\>db2 select hex(col1) from big5_tab

1
--------------------
EFBCA2EFBCA9EFBCA720

  已選取 1 個記錄。

C:\>db2 select hex(col1) from big5_tab fetch first 1 row only

1
--------------------
A2D0A2D7A2D5A1D0A2B4

  已選取 1 個記錄。

/* And it happened on Multi-Byte Characters */


/*
  Back to BIG5DB
  Create Nickname UTF8_TAB2 on BIG5DB
*/


C:\>db2 connect to big5db

  資料庫連線資訊

 資料庫伺服器      = DB2/NT 9.5.0
 SQL 授權 ID      = ORION
 本地資料庫別名     = BIG5DB

C:\>db2 create table big5_tab2 ( col1 integer,col2 varchar(10) ) in userspace1
DB20000I SQL 指令已順利完成。

/* insert testing data */
inesrt into big5_tab2 values (1,'odd'),(2,'ODD')

/* Connect ORIONDB again */

C:\>db2 connect to oriondb

  資料庫連線資訊

 資料庫伺服器      = DB2/NT 9.5.0
 SQL 授權 ID      = ORION
 本地資料庫別名     = ORIONDB

C:\>db2 create nickname orion.big5_tab2 for big5db.orion.big5_tab2
DB20000I SQL 指令已順利完成。

C:\>db2 select col1,col2,hex(col2) from big5_tab2 fetch first 2 row only

COL1 COL2  3
----- ------ --------------------
  1 odd  6F6464
  2 ODD A2DDA2D2A2D2

  已選取 2 個記錄。

C:\>db2 select col1,col2,hex(col2) from big5_tab2

COL1 COL2  3
---- ------ --------------------
  1 odd  6F6464
  2 ODD EFBCAFEFBCA4EFBCA4

  已選取 2 個記錄。

2008年9月23日 星期二

Get numbers from Multi or Single-byte characters using Oracle10g


/*
  Purpose: eliminate none digital data from strings
  Using functions: TO_SINGLE_BYTE、ASCII、SYS_CONNECT_BY_PATH、OLAP Function
  And Recursive SQL: Connect by
*/


/* Marvelous Function: TO_SINGLE_BYTE */

SELECT TO_SINGLE_BYTE('097年0101#NO.001') FROM DUAL

/* Result is */

097年0101#NO.001

/* Chinese characters also turn out to be single-byte */

SELECT SUBSTR(TO_SINGLE_BYTE('097年0101#NO.001'),4,1) FROM DUAL

/* Result is */




/*
  Using Recursive SQL to separate each character
  Choose number whichever ascii code between 48 and 59
  Columns (ONO、PRECURSOR) made this inner view a self join-like table
  Column LENS made of Olap function which counting numbers
*/


SELECT ROWNUM ONO,DATA,ROWNUM - 1 PRECURSOR,COUNT(*) OVER() LENS
FROM  (SELECT TXT,
        (CASE WHEN ASCII(SUBSTR(TXT,LEVEL,1)) BETWEEN 48 AND 59 THEN
            SUBSTR(TXT,LEVEL,1) END) DATA
     FROM (SELECT TO_SINGLE_BYTE('097#01-NO-290013976') TXT
         FROM DUAL) T
     CONNECT BY LEVEL <= LENGTH(TXT)
     ) T
WHERE DATA IS NOT NULL


/* Result is */




/*
  use inner view above to make up numbers
  SYS_CONNECT_BY_PATH keeps each recursive result of data
*/


SELECT TXT,REPLACE(SYS_CONNECT_BY_PATH(DATA,' '),' ','') HIST
FROM  (SELECT TXT,ROWNUM ONO,DATA,ROWNUM - 1 PRECURSOR,
         COUNT(*) OVER() LENS
     FROM (SELECT TXT,
             (CASE WHEN ASCII(SUBSTR(TXT,LEVEL,1)) BETWEEN 48 AND 59
                 THEN SUBSTR(TXT,LEVEL,1) END) DATA
         FROM (SELECT TO_SINGLE_BYTE('097#01-NO-290013976') TXT
              FROM DUAL) T
         CONNECT BY LEVEL <= LENGTH(TXT)
        ) T WHERE DATA IS NOT NULL
     )T2
WHERE ONO = LENS
START WITH ONO = 1
CONNECT BY PRIOR ONO = PRECURSOR


/* Result is */

2008年9月22日 星期一

Get numbers from Multi or Single-byte characters using DB2 9


/*
  Purpose: 將數字(全形或半行)從字串中篩選出來。
  Using DB2 functions: HEX、ASCII、SUBSTRING、CHAR_LENGTH
  And Recursive SQL
*/


/*
  利用 Recursive SQL 的特性將字元一個一個拆開
  再運用 HEX 及 ASCII 判斷字元是否為數字,是則取出,否則轉空白
  同樣利用 Recursive SQL 的特性將取出的數字 pipe 起來
*/


WITH N(X,TXT,T1,LENS) AS
(
SELECT 1 X,TXT,
     CASE WHEN HEX(SUBSTRING(TXT,1,1,CODEUNITS32)) BETWEEN 'EFBC90'
                                AND 'EFBC99' THEN
           RIGHT(HEX(SUBSTRING(TXT,1,1,CODEUNITS32)),1)
        WHEN ASCII(SUBSTRING(TXT,1,1,CODEUNITS32)) BETWEEN 48
                                AND 57 THEN
           SUBSTRING(TXT,1,1,CODEUNITS32)
     ELSE '' END T1,CHAR_LENGTH(TXT,CODEUNITS32) LENS
FROM  (SELECT '文097字0101-123' TXT FROM SYSIBM.SYSDUMMY1) T
UNION  ALL
SELECT N.X + 1,TXT,T1 ||
    CASE WHEN HEX(SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)) BETWEEN 'EFBC90'
                                  AND 'EFBC99' THEN
          RIGHT(HEX(SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)),1)
       WHEN ASCII(SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)) BETWEEN 48
                                  AND 57 THEN
          SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)
    ELSE '' END T1,N.LENS
FROM  N
WHERE N.X + 1 <= CHAR_LENGTH(TXT,CODEUNITS32)
)
SELECT * FROM N
ORDER BY TXT,X

/* 選取結果如下 */


※ 如果只要選取結果,則在加上 where 條件,Recursive 的次數 = 字串長度即可
/* 建立測試 Table,測試多筆資料 */

CREATE TABLE ORION_TEXT
(
   TXT VARCHAR(60)
) IN USERSPACE1

/* 建立測試資料 */

INSERT INTO ORION_TEXT VALUES ('文097字號38092 7')
INSERT INTO ORION_TEXT VALUES ('作廢文096字號0083216')
INSERT INTO ORION_TEXT VALUES ('作廢文096字號0083216')
INSERT INTO ORION_TEXT VALUES ('')
INSERT INTO ORION_TEXT VALUES ('NO9701-091388')


/*
  將使用 dummy table 的地方改為 ORION_TEXT
  加入選取條件為 X = LENS
*/


WITH N(X,TXT,T1,LENS) AS
(
SELECT 1 X,TXT,
     CASE WHEN HEX(SUBSTRING(TXT,1,1,CODEUNITS32)) BETWEEN 'EFBC90'
                                AND 'EFBC99' THEN
           RIGHT(HEX(SUBSTRING(TXT,1,1,CODEUNITS32)),1)
        WHEN ASCII(SUBSTRING(TXT,1,1,CODEUNITS32)) BETWEEN 48
                                AND 57 THEN
           SUBSTRING(TXT,1,1,CODEUNITS32)
     ELSE '' END T1,CHAR_LENGTH(TXT,CODEUNITS32) LENS
FROM  ORION_TEXT
UNION  ALL
SELECT N.X + 1,TXT,T1 ||
    CASE WHEN HEX(SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)) BETWEEN 'EFBC90'
                                  AND 'EFBC99' THEN
          RIGHT(HEX(SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)),1)
       WHEN ASCII(SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)) BETWEEN 48
                                  AND 57 THEN
          SUBSTRING(TXT,N.X + 1,1,CODEUNITS32)
    ELSE '' END T1,N.LENS
FROM  N
WHERE N.X + 1 <= CHAR_LENGTH(TXT,CODEUNITS32)
)
SELECT TXT,T1 FROM N
WHERE X = LENS
ORDER BY TXT,X

/* 結果如下圖 */

New decimal floating-point data type - DB2 9


/*
  DB2 9 增加了一個提升 decimal 的資料型態,叫做 decfloat
  除了增加數值資料運算時的精確性之外,運算的效能據說非常好
  但是,必須搭配 IBM 的處理器 POWER6,才能感受它的效能
  由於 decfloat 有遵照 IEEE 754 浮點表示法,
  在一般處理器上進行運算,資料並不會有問題,
  只是效能跟 decimal 沒什麼差別
*/


/* 建立測試 table */

create table datatype_test
(
  tbcreator varchar(16),
  amt1 decimal(19,2),
  amt2 decfloat(16),
  amt3 decfloat(34)
) in userspace1
DB20000I SQL 指令已順利完成。


/*
  看一下在 system table 裡 table layout
  decfloat 的欄位跟 float(doulbe) 在 SCALE 上都是給0
  ※ decfloat 的 LENGTH 是 IN BYTES
*/


select name,coltype,length,scale
from sysibm.syscolumns
where tbname = 'DATATYPE_TEST'
order by colno

NAME       COLTYPE LENGTH SCALE
---------------- -------- ------ ------
TBCREATOR    VARCHAR   16   0
AMT1       DECIMAL   19   2
AMT2       DECFLOAT   8   0
AMT3       DECFLOAT  16   0

  已選取 4 個記錄。


/* 新增測試資料,金額欄位取亂數 */

insert into datatype_test
select tbcreator,decimal(rand() * 10000000,19,2),
    cast(rand() * 10000000.00 as decfloat(16)),
    cast(rand() * 10000000.00 as decfloat(34))
from sysibm.syscolumns
DB20000I SQL 指令已順利完成。

insert into datatype_test
select tbcreator,decimal(rand() * 10000000,19,2),
    cast(rand() * 10000000.00 as decfloat(16)),
    cast(rand() * 10000000.00 as decfloat(34))
from sysibm.syscolumns
DB20000I SQL 指令已順利完成。

insert into datatype_test
select tbcreator,decimal(rand() * 10000000,19,2),
    cast(rand() * 10000000.00 as decfloat(16)),
    cast(rand() * 10000000.00 as decfloat(34))
from sysibm.syscolumns
DB20000I SQL 指令已順利完成。

/* 檢查總筆數 */

select count(*) from datatype_test

1
-----------
   16272

  已選取 1 個記錄。


/*
  選兩筆來看看
  decfloat 雖然在 SCALE 上都是給0,小數點還是有
*/


select * from datatype_test fetch first 2 row only

TBCREATOR    AMT1      AMT2       AMT3
---------  ------------- ------------------ -----------------
DB2EXT    1933042.39  5635853.144932401 12512.58888515885
DB2EXT    4798730.43  5850093.081453902 8087405.0111392559

  已選取 2 個記錄。

/* 做一下reorgchk */

reorgchk update statistics on table orion.datatype_test



/* 使用 sql explain 分別對不同金額欄位做加總 */

C:\>db2expln -database SAMPLE -g -statement "select sum(amt1) from datatype_test" -o c:\stmtfile1.log

C:\>db2expln -database SAMPLE -g -statement "select sum(amt2) from datatype_test" -o c:\stmtfile2.log

C:\>db2expln -database SAMPLE -g -statement "select sum(amt3) from datatype_test" -o c:\stmtfile3.log


/* 發現無論對哪一個欄位運算效能都一樣,所以要搭配IBM POWER6處理器才看得出來 */


Estimated Cost = 138.325012
Estimated Cardinality = 1.000000

Access Table Name = ORION.DATATYPE_TEST ID = 2,33
| #Columns = 1
| Avoid Locking Committed Data
| Relation Scan
| | Prefetch: Eligible
| Lock Intents
| | Table: Intent Share
| | Row : Next Key Share
| Sargable Predicate(s)
| | Predicate Aggregation
| | | Column Function(s)
Aggregation Completion
| Column Function(s)
Return Data to Application
| #Columns = 1
End of section

Optimizer Plan:
   Rows
  Operator
   (ID)
   Cost
    
    1
  RETURN
   ( 1)
  138.325
    |
    1
   GRPBY
   ( 2)
  138.325
    |
   16272
   TBSCAN
   ( 3)
   136.964
    |
   16272
 Table:
 ORION
 DATATYPE_TEST

/* 測試數值欄位 ALTER 成 DECFLOAT */

create table test
(
  col1 smallint,
  col2 integer,
  col3 bigint,
  col4 decimal(19,2),
  col5 float,
  col6 decfloat(16)
) in userspace1
DB20000I SQL 指令已順利完成。

/* SYSTEM TABLE 裡的 TABLE LAYOUT */

select name,coltype,length,scale
from sysibm.syscolumns
where tbname = 'TEST'
order by colno

NAME       COLTYPE LENGTH SCALE
---------------- -------- ------ ------
COL1       SMALLINT   2    0
COL2       INTEGER    4    0
COL3       BIGINT    8    0
COL4       DECIMAL   19    2
COL5       DOUBLE    8    0
COL6       DECFLOAT   8    0

  已選取 6 個記錄。

/* ALTER SMALLINT 欄位成 DECFLOAT */

alter table test alter column col1 set data type decfloat(16)
DB20000I SQL 指令已順利完成。

reorg table test
DB20000I REORG 指令已順利完成。

/* ALTER INTEGER 欄位成 DECFLOAT */

alter table test alter column col2 set data type decfloat(16)
DB20000I SQL 指令已順利完成。

reorg table test
DB20000I REORG 指令已順利完成。

/* ALTER BIGINT 欄位成 DECFLOAT(注意長度) */

alter table test alter column col3 set data type decfloat(34)
DB20000I SQL 指令已順利完成。

reorg table test
DB20000I REORG 指令已順利完成。

/* ALTER DECIMAL 欄位成 DECFLOAT(注意長度) */

alter table test alter column col4 set data type decfloat(34)
DB20000I SQL 指令已順利完成。

reorg table test
DB20000I REORG 指令已順利完成。

/* ALTER FLOAT 欄位成 DECFLOAT(注意長度) */

alter table test alter column col5 set data type decfloat(34)
DB20000I SQL 指令已順利完成。

reorg table test
DB20000I REORG 指令已順利完成。

/* ALTER DECFLOAT 長度 */

alter table test alter column col6 set data type decfloat(34)
DB20000I SQL 指令已順利完成。

reorg table test
DB20000I REORG 指令已順利完成。

/* 但是已經ALTER成DECFLOAT的欄位,似乎無法再變更為其它數值欄位 */

alter table test alter column col1 set data type decimal(31)
DB21034E 指令被當作 SQL 陳述式處理,因為他不是有效的「指令行處理器」指令。 在SQL 處理程序期間,他已傳回:
SQL0190N ALTER TABLE "ORION.TEST" 為直欄 "COL1"所指定的屬性與現存直欄不相容。 SQLSTATE=42837

alter table test alter column col1 set data type bigint
DB21034E 指令被當作 SQL 陳述式處理,因為他不是有效的「指令行處理器」指令。 在SQL 處理程序期間,他已傳回:
SQL0190N ALTER TABLE "ORION.TEST" 為直欄 "COL1"所指定的屬性與現存直欄不相容。 SQLSTATE=42837

alter table test alter column col1 set data type float
DB21034E 指令被當作 SQL 陳述式處理,因為他不是有效的「指令行處理器」指令。 在SQL 處理程序期間,他已傳回:
SQL0190N ALTER TABLE "ORION.TEST" 為直欄 "COL1"所指定的屬性與現存直欄不相容。 SQLSTATE=42837

2008年9月18日 星期四

"Alter Table" a bit change - DB2 9


/*
  DB2 8.2 在 ALTER TABLE COLUMN 上的功能很陽春。
  它只能變更 VARCHAR 欄位的長度,對其他型態的異動是完全無能為力的。

  DB2 9 雖然有改進,可是卻必須在變更後對 TABLE 做 REORG,
  (除了 VARCHAR 及 VARGRAPHIC 之外)
  
  DB2 9 型態的轉換只要不是型態完全不相關,
  只要注意長度不要小於原先的長度,大致上都還能做變更
  SQL Reference Volumne 2 有表列
*/


/* DB2 8.2 只有對 VARCHAR ALTER 時是 okay 的*/

CREATE TABLE TEST
(
   COL1 VARCHAR(5),
   COL2 CHAR(1)
) IN USERSPACE1;

ALTER TABLE TEST ALTER COLUMN COL1 SET DATA TYPE VARCHAR(10)
DB20000I SQL 指令已順利完成。

ALTER TABLE TEST ALTER COLUMN COL2 SET DATA TYPE CHAR(3)
DB21034E 命令被當作 SQL 陳述式處理, 因為它不是有效的「命令行處理器」命令。在SQL 處理程序期間,它已傳回:
SQL0190N ALTER TABLE "DB2ADMIN.TEST" 為 "COL2" 直欄指定的屬性與現存直欄不相容。 SQLSTATE=42837

/* DB2 9 */
/* create 測試 table */

create table altering_tab
(
  col1 smallint,
  col2 char(1),
  col3 varchar(10),
  col4 decimal(10,2)
) in userspace1
DB20000I SQL 指令已順利完成。

/* 新增測試資料 */

insert into altering_tab values (1,'A','A123456789',20.6),
                  (2,'B','B123456789',120.9),
                  (18,'C','C123456789',99.99),
                  (200,'G','G123456789',100.65)
DB20000I SQL 指令已順利完成。

/* 將 col1 型態變更為 integer */

alter table altering_tab alter column col1 set data type integer
DB20000I SQL 指令已順利完成。

/* 可以對 table 做 select */

select * from altering_tab

COL1     COL2 COL3    COL4
----------- ---- ---------- ------------
     1 A  A123456789     20.60
     2 B  B123456789    120.90
     18 C  C123456789     99.99
    200 G  G123456789    100.65

  已選取 4 個記錄。

/* 但無法做 DML */

insert into altering_tab values (7100,'X','X123456789',999.98)
DB21034E 指令被當作 SQL 陳述式處理,因為他不是有效的「指令行處理器」指令。 在SQL 處理程序期間,他已傳回:
SQL0668N 表格 "ORION.ALTERING_TAB" 上不容許作業,原因碼為 "7"。SQLSTATE=57016

/* 須要做 REORG */

reorg table altering_tab
DB20000I REORG 指令已順利完成。

/* 之後才能對 TABLE 做 DML */

insert into altering_tab values (7100,'X','X123456789',999.98)
DB20000I SQL 指令已順利完成。

/* 變更 VARCHAR 欄位則無須做 REORG */

alter table altering_tab alter column col3 set data type varchar(16)
DB20000I SQL 指令已順利完成。

insert into altering_tab values (9999,'Y','Y123456789012345',1259.77)
DB20000I SQL 指令已順利完成。

/* 另外須要做 REORG 的還有 DROP 欄位的時候 */

alter table altering_tab drop column col4
DB20000I SQL 指令已順利完成。

insert into altering_tab values (333,'K','K555')
DB21034E 指令被當作 SQL 陳述式處理,因為他不是有效的「指令行處理器」指令。 在SQL 處理程序期間,他已傳回:
SQL0668N 表格 "ORION.ALTERING_TAB" 上不容許作業,原因碼為 "7"。SQLSTATE=57016

reorg table altering_tab
DB20000I REORG 指令已順利完成。

insert into altering_tab values (333,'K','K555')
DB20000I SQL 指令已順利完成。

2008年9月17日 星期三

Two phase commit using DB2 9


/*
  DB2 的 Two phase commit 是很久的東西了。但之前一直沒去測,後來才知道其實很簡單。
  
  My Scenario:
    DB1:SAMPLE   TABLE: N_CONFIG
    DB2:ORIONDB  TABLE: ORION_CFG、TRC_LOG
    PROCEDURE: SP_2PHASECOMMIT 建在ORIONDB。
          先新增N_CONFIG再新增ORION_CFG。
          新增失敗則ROLLBACK。
          留LOG: TRC_LOG。
    FEDERATION 的設定參考
    Global variable and federated stored procedure using DB2 9
    http://orionsdatabase.blogspot.com/2008/09/global-variable-and-federated-stored.html
*/



/*
  DB:ORIONDB
  Federation: Server 參數 DB2_TWO_PHASE_COMMIT 的設定
*/


/* 不使用 DB2CC 則可直接下 SQL */

ALTER SERVER SAMPLE OPTIONS (ADD DB2_TWO_PHASE_COMMIT 'Y')


※ 不設定為 Y 。未來執行PROCEDURE會失敗。錯誤訊息為 -30090,表示不支援這種TWO PHASE COMMIT


/* 在 DB SAMPLE 上建立 N_CONFIG */

CREATE TABLE N_CONFIG
(
   KIND   VARCHAR(32),
   VALUE   VARCHAR(32),
   DESC   VARCHAR(128)
) IN USERSPACE1;

/* 在 DB ORIONDB 上建立 ORION_CFG 及 TRC_LOG */

CREATE TABLE ORION_CFG
(
   KIND   VARCHAR(32) NOT NULL PRIMARY KEY,
   VALUE   VARCHAR(32),
   DESC   VARCHAR(128)
) IN USERSPACE1;

CREATE TABLE TRC_LOG
(
   SYSDT     TIMESTAMP,
   ERROR_CODE  INTEGER,
   INPUT_VALUE  VARCHAR(1024)
) IN USERSPACE1;

/* 在 DB ORIONDB 上為 DB SAMPLE 的 N_CONFIG 建立 NICKNAME */

CREATE NICKNAME ORION.N_CONFIG FOR SAMPLE.ORION.N_CONFIG;

/* 在 DB ORIONDB 建立 stored procedure */

CREATE PROCEDURE SP_2PHASECOMMIT(IN iC1 VARCHAR(32),
                   IN iC2 VARCHAR(32),
                   IN iC3 VARCHAR(128))
SPECIFIC SP_2PHASECOMMIT
LANGUAGE SQL
BEGIN
   
   DECLARE SQLCODE  INTEGER DEFAULT 0;
   DECLARE RETCODE  INTEGER DEFAULT 0;

   DECLARE CONTINUE HANDLER
   FOR SQLEXCEPTION,SQLWARNING,NOT FOUND
   SET RETCODE = SQLCODE;

   INSERT INTO N_CONFIG(KIND,VALUE,DESC)
   VALUES (iC1,iC2,iC3);

   IF (retcode <> 0) AND (retcode <> 100) THEN
      GOTO LABEL1;
   END IF;

   INSERT INTO ORION_CFG(KIND,VALUE,DESC)
   VALUES (iC1,iC2,iC3);

   IF (retcode <> 0) AND (retcode <> 100) THEN
      GOTO LABEL1;
   END IF;

   INSERT INTO TRC_LOG
   VALUES (CURRENT TIMESTAMP,retcode,RTRIM(iC1) || '-' ||
                       RTRIM(iC2) || '-' ||
                       RTRIM(iC3));
   COMMIT;
   RETURN retcode;
LABEL1:
   ROLLBACK;
   INSERT INTO TRC_LOG
   VALUES (CURRENT TIMESTAMP,retcode,RTRIM(iC1) || '-' ||
                       RTRIM(iC2) || '-' ||
                       RTRIM(iC3));
   COMMIT;
   RETURN retcode;
END



※ 建立時會出現以下 warning :
   SQL1179W 稱為 "ORION.P6301784" 的 "PACKAGE" 可能要求呼叫者對資料來源物件具有必要的專用權。 SQLSTATE=01639
※ 不用理會這個 warning


/* 測試 */

C:\>db2 call sp_2phasecommit('SERVER','10.7.72.88','SERVER IP')

傳回狀態 = 0

C:\>db2 select * from n_config

KIND        VALUE       DESC
----------------- ---------------- ----------------
SERVER       10.7.72.88    SERVER IP

  已選取 1 個記錄。

C:\>db2 select * from orion_cfg

KIND        VALUE       DESC
----------------- ---------------- ----------------
SERVER       10.7.72.88    SERVER IP

  已選取 1 個記錄。

C:\>DB2 SELECT * FROM TRC_LOG

SYSDT             ERROR_CODE INPUT_VALUE
-------------------------- ----------- -----------------------------------------
2008-09-17-16.31.19.299000      0  SERVER-10.7.72.88-SERVER IP

  已選取 1 個記錄。

/* 測試duplicate,做rollback */

C:\>db2 call sp_2phasecommit('SERVER','10.7.72.88','SERVER IP')

傳回狀態 = -803

C:\>db2 select * from n_config

KIND        VALUE       DESC
----------------- ---------------- ----------------
SERVER       10.7.72.88    SERVER IP

  已選取 1 個記錄。


C:\>db2 select * from orion_cfg

KIND        VALUE       DESC
----------------- ---------------- ----------------
SERVER       10.7.72.88    SERVER IP

  已選取 1 個記錄。


C:\>db2 select * from trc_log

SYSDT             ERROR_CODE INPUT_VALUE
-------------------------- ----------- -----------------------------------------
2008-09-17-16.31.19.299000      0 SERVER-10.7.72.88-SERVER IP
2008-09-17-16.31.44.655000    -803 SERVER-10.7.72.88-SERVER IP

已選取 2 個記錄。

2008年9月11日 星期四

Partitioned MQT (II) using DB2 9


/*
My scenario: 利用已經做好的 MQT MQT_DAY_LIST,
        假設現行資料檔 DAY_LIST 有異動
        MQT_DAY_LIST 應該如何去做 REFRESH
*/

/* 刪除 DAY_LIST 所有大於 2008-09-11 的日期 */

delete from day_list where dt > '2008-09-11'
DB20000I The SQL command completed successfully.

/* MQT_DAY_LIST 還未受影響 */

select count(*) from mqt_day_list

1
-----------
   1096

 1 record(s) selected.

/* MQT_DAY_LIST 的 PARTITIONS 如下 */

PARTITIONNAME   LOWVALUE    HIGHVALUE
----------------- --------------- -----------------
PART0       '2008-01-01'  '2008-12-31'
PART2007     '2007-01-01'  '2007-12-31'
PART2006     '2006-01-01'  '2006-12-31'

 3 record(s) selected.

/* 將 PARTITION PART2007 DETACH 掉 */
alter table mqt_day_list detach partition part2007 into mqt_part2007
SQL3601W The statement caused one or more tables to automatically be placed
in the Set Integrity Pending state. SQLSTATE=01586

/* 檢查完整性同時做REFRESH */

set integrity for mqt_day_list immediate checked
DB20000I The SQL command completed successfully.

/* 將 PARTITION PART2006 DETACH 掉 */

alter table mqt_day_list detach partition part2006 into mqt_part2006
SQL3601W The statement caused one or more tables to automatically be placed
in the Set Integrity Pending state. SQLSTATE=01586

/* 檢查完整性同時做REFRESH */

set integrity for mqt_day_list immediate checked
DB20000I The SQL command completed successfully.

/* MQT_DAY_LIST 還有多少筆數 */

select count(*) from mqt_day_list

1
-----------
     255

 1 record(s) selected.

/* 把 MQT_DAY_LIST 變更為一般的 Table */

alter table mqt_day_list drop materialized query
DB20000I The SQL command completed successfully.

/* 把才 DETACH 的PARTITION 分別再 ATTACH 回來 */

alter table mqt_day_list attach partition part2007 starting '2007-01-01' ending '2007-12-31' from mqt_part2007
SQL3601W The statement caused one or more tables to automatically be placed in the Set Integrity Pending state. SQLSTATE=01586

alter table mqt_day_list attach partition part2006 starting '2006-01-01' ending '2006-12-31' from mqt_part2006
DB20000I The SQL command completed successfully.

/* 檢查完整性同時做REFRESH */

set integrity for mqt_day_list immediate checked
DB20000I The SQL command completed successfully.

/* 新的DAY_LIST資料進來+2007年度+2006年度資料 */

select count(*) from mqt_day_list

1
-----------
     985

 1 record(s) selected.

/* 把 MQT_DAY_LIST 變更為MQT Table */

alter table mqt_day_list add materialized query
(select dt from day_list)
data initially deferred refresh deferred
DB20000I The SQL command completed successfully.

/* 由於還未經過 SET INTEGRITY,因此沒辦法做 SELECT */

select count(*) from mqt_day_list

1
-----------
SQL0668N Operation not allowed for reason code "1" on table
"DB2ADMIN.MQT_DAY_LIST". SQLSTATE=57016


/*
 這裡一樣不能做checked,否則 MQT 重新 REFRESH 後,就只剩 DAY_LIST 的資料
 這也是為什麼需要將 MQT 變更為一般的 TABLE 再來做 ATTACH
*/


set integrity for mqt_day_list all immediate unchecked
DB20000I The SQL command completed successfully.

/* 接著就可以檢查筆數是否正確 */

select count(*) from mqt_day_list

1
-----------
     985

 1 record(s) selected.

Partitioned MQT (I) using DB2 9


/*
My scenario : 先完成一個有歷史資料的 Materialized Query Table,
        但 MQT create 在只有現行資料的 Table 上,
        歷史資料用 attach 方式進去。

1) 前置處理(create table & insert data):
    day_list存2008資料,day_2007存2007資料,day_2006存2006資料。
    create partitioned mqt table
        mqt建立在day_list上。
    how to attach
        使mqt_day_list有2008資料,也有歷史記錄2007及2006。
*/

/* 1) initiation - create table */
/*   使用之前用的day_list */

create table day_list
(
  dt date
) partition by range(dt)
(starting '2008-01-01' ending '2008-12-31' every 3 months)

/*   新增2008日期資料 */

INSERT INTO DAY_LIST
SELECT DATE(RTRIM(CHAR(YEAR(CURRENT DATE)))||'-01-01') + N DAY
FROM (SELECT (ROW_NUMBER() OVER() - 1) N
    FROM SYSIBM.SYSTABLES FETCH FIRST 366 ROW ONLY) D
WHERE YEAR(DATE(RTRIM(CHAR(YEAR(CURRENT DATE)))||'-01-01')+N DAY) = YEAR(CURRENT DATE);

/*   建立 day_2007 */

create table day_2007
(
  dt date
) in userspace1;

/*   新增2007日期資料 */

INSERT INTO DAY_2007
SELECT DATE(RTRIM(CHAR(2007))||'-01-01') + N DAY
FROM (SELECT (ROW_NUMBER() OVER() - 1) N
    FROM SYSIBM.SYSTABLES FETCH FIRST 366 ROW ONLY) D
WHERE YEAR(DATE(RTRIM(CHAR(2007))||'-01-01')+N DAY) = 2007;

/*   建立 day_2006 */

create table day_2006
(
  dt date
) in userspace1;

/*   新增2006日期資料 */

INSERT INTO DAY_2006
SELECT DATE(RTRIM(CHAR(2006))||'-01-01') + N DAY
FROM (SELECT (ROW_NUMBER() OVER() - 1) N
    FROM SYSIBM.SYSTABLES FETCH FIRST 366 ROW ONLY) D
WHERE YEAR(DATE(RTRIM(CHAR(2006))||'-01-01')+N DAY) = 2006;


/*   CREATE MQT TABLE */

create table mqt_day_list as
(
  select dt
  from  day_list
)DATA INITIALLY DEFERRED REFRESH deferred
PARTITION BY RANGE(dt)
(STARTING '2008-01-01' ENDING '2008-12-31')
in userspace1;

/*   將資料滾進 MQT */

set integrity for mqt_day_list immediate checked

/*   或者使用REFRESH TABLE都可以 */

refresh table mqt_day_list

/*   檢查一下mqt的partition */

select datapartitionname,datapartitionid,lowvalue,highvalue
from sysibm.sysdatapartitions
where tabname = 'MQT_DAY_LIST'

PARTITIONNAME      LOWVALUE      HIGHVALUE
--------------------- ------------------ ----------------
PART0          '2008-01-01'    '2008-12-31'

 1 record(s) selected.

/*   確定資料滾進來 */

select count(*) from mqt_day_list

1
-----------
     366

 1 record(s) selected.

/*   讓 mqt 有 2007 及 2006 歷史資料 */
/*   先使 MQT Table 變成普通的 table */

alter table mqt_day_list drop materialized query
DB20000I The SQL command completed successfully.

/*   將先前做好的day_2007 attach上來 */

alter table mqt_day_list attach partition part2007 starting '2007-01-01' ending '2007-12-31' from day_2007
SQL3601W The statement caused one or more tables to automatically be placed in the Set Integrity Pending state. SQLSTATE=01586

/*   檢查完整性 */

set integrity for mqt_day_list immediate checked
DB20000I The SQL command completed successfully.

/*   將先前做好的day_2006 也attach上來 */

alter table mqt_day_list attach partition part2006 starting '2006-01-01' ending '2006-12-31' from day_2006
SQL3601W The statement caused one or more tables to automatically be placed in the Set Integrity Pending state. SQLSTATE=01586

/*   檢查完整性 */

set integrity for mqt_day_list immediate checked
DB20000I The SQL command completed successfully.

/*   把變成普通 TABLE 的 MQT 再 ALTER 回 MQT Table */

alter table mqt_day_list add materialized query
(select dt from day_list) data initially deferred refresh deferred


/*
   這時一定要unchecked
   因為一旦checked,mqt 又會從day_list refresh資料進來
*/


C:\>db2 set integrity for mqt_day_list all immediate unchecked
DB20000I The SQL command completed successfully.


/*   檢查mqt筆數 */

C:\>db2 select count(*) from mqt_day_list

1
-----------
    1096

 1 record(s) selected.

Table Partitioning (II) using DB2 9


/*
 關於 HIGHVALUE 的值看起來跟 LOWVALUE overlap 的問題
*/

/* 首先,先恢復原狀 */

create table day_list
(
   dt date
) partition by range(dt)
(starting '2008-01-01' ending '2008-12-31' every 3 months)

DB20000I The SQL command completed successfully.


/*
 開啟 db2cc
 原來 SYSIBM.SYSDATAPARTITIONS 還有一個欄位 HIGHINCLUSIVE
 N 是不包含 HIGHVALUE 的值,Y 則是要包含。
 所以除了 PART3 是有包含 '2008-12-31' 之外,其它都是設成 N
*/



/* 應當是與建立時下的語法有關 */

partition by range(dt)
(starting '2008-01-01' ending '2008-12-31' every 3 months)

/* 將 part0 detach */

alter table day_list detach partition part0 into tab_reuse0
DB20000I The SQL command completed successfully.

/* 將 part0 attach 回來 */

alter table day_list attach partition part0 starting '2008-01-01' ending '2008-03-31' from tab_reuse0
SQL3601W The statement caused one or more tables to automatically be placed
in the Set Integrity Pending state. SQLSTATE=01586

/* 檢查完整性 */

set integrity for day_list immediate checked
DB20000I The SQL command completed successfully.


/*
 db2cc 裡 SYSIBM.SYSDATAPARTITIONS 欄位 HIGHINCLUSIVE 值在 PART0 已經改為 Y,
 且值即是所給定的 ending 值 '2008-03-31'
*/





/* 
 另外,順便用 db2cc 看一下有哪些 tablespaces
 ※ 要特別注意 IBMDB2SAMPLEREL 這個 tablespace
*/




/*
 選擇 DAY_LIST 這個 TABLE (它的 Table space 是 Partitioned Table)
 點右鍵時多了一個選項 Open Data Partitions
*/




/* 
 選擇Open Data Partitions 之後出現 Data Partition 的內容 
 Partitions 的 Tablespace 就是放在 IBMDB2SAMPLEREL
 另外,Starting Value 就是 LOWVALUE、
 Ending Value 就是 HIGHVALUE
 Ending Value Inclusive 就是 HIGHINCLUSIVE 的內容
*/

2008年9月10日 星期三

Table Partitioning (I) using DB2 9


/*
用 free download 下來的 DB2 EXPRESS-C v9.5 如果沒有購買有效的 DB2 Enterprise Server Edition 授權,在 create partition table 時,則會出現以下錯誤訊息:


SQL8027N 正在使用表格分割功能,但沒有 DB2 Enterprise Server Edition 授權。 DB2 偵測到已使用表格分割功能,但沒有 DB2 Enterprise Server Edition 授權。請確定已向 IBM 業務代表或授權經銷商購買有效的 DB2 Enterprise Server Edition 授權,並已使用「DB2 授權中心」或 db2licm 指令行公用程式更新授權。如需更新授權的相關資訊,請參閱您的平台的「快速入門」手冊


真是 Orz ......

好在上回拿到一個 VMware 裡的 DB2 是經過授權的,可以拿來測試看看
*/


/* 先建一個測試 Table */

create table day_list
(
  dt date
) partition by range(dt)
(starting '2008-01-01' ending '2008-12-31' every 3 months)

/* 從 db2cc 看建立結果 */



/* insert 2008 一整年的日期 */


INSERT INTO DAY_LIST
SELECT DATE(RTRIM(CHAR(YEAR(CURRENT DATE)))||'-01-01') + N DAY
FROM (SELECT (ROW_NUMBER() OVER() - 1) N
    FROM SYSIBM.SYSTABLES FETCH FIRST 366 ROW ONLY) D
WHERE YEAR(DATE(RTRIM(CHAR(YEAR(CURRENT DATE)))||'-01-01')+N DAY) =
    YEAR(CURRENT DATE)


/* 檢查一下總筆數 */

select count(*) from day_list

/* 傳回 366 筆 */

1
-----------
     366

 1 record(s) selected.

/** 這裡的HIGHVALUE 很奇怪,之後還要再測試看看 **/
/* 從 SYSTEM TABLE 看 Partition */

select datapartitionname,datapartitionid,lowvalue,highvalue
from sysibm.sysdatapartitions
where tabname = 'DAY_LIST'

PARTITIONNAME      LOWVALUE          HIGHVALUE
---------------------- ------------------------ -------------------------
PART0          '2008-01-01'        '2008-04-01'
PART1          '2008-04-01'        '2008-07-01'
PART2          '2008-07-01'        '2008-10-01'
PART3          '2008-10-01'        '2008-12-31'

 4 record(s) selected.

/* 把 partition part0 從 day_list 中 detach 掉 */

alter table day_list detach partition part0 into tab_reuse0
DB20000I The SQL command completed successfully.

/* detach 的資料建到 tab_reuse0 去 */



/* 再從 SYSTEM TABLE 看 Partition */

select datapartitionname,datapartitionid,lowvalue,highvalue
from sysibm.sysdatapartitions
where tabname = 'DAY_LIST'

PARTITIONNAME     LOWVALUE          HIGHVALUE
---------------------- ------------------------ -------------------------
PART1          '2008-04-01'        '2008-07-01'
PART2          '2008-07-01'        '2008-10-01'
PART3          '2008-10-01'        '2008-12-31'

 3 record(s) selected.

/* 清空 tab_reuse0 裡的資料 */

alter table tab_reuse0 activate not logged initially with empty table
DB20000I The SQL command completed successfully.

/* 也不做完整性檢查 */

set integrity for tab_reuse0 off
DB20000I The SQL command completed successfully.

/* 將 tab_reuse0 attach 回去,雖然有 warning 但是 partition 已經加回去了 */

alter table day_list attach partition part0 starting '2008-01-01' ending '2008-03-31' from tab_reuse0

SQL3601W The statement caused one or more tables to automatically be placed
in the Set Integrity Pending state. SQLSTATE=01586

/* 從 SYSTEM TABLE 看 Partition */

select datapartitionname,datapartitionid,lowvalue,highvalue
from sysibm.sysdatapartitions
where tabname = 'DAY_LIST'

PARTITIONNAME      LOWVALUE          HIGHVALUE
---------------------- ------------------------ -------------------------
PART1          '2008-04-01'        '2008-07-01'
PART2          '2008-07-01'        '2008-10-01'
PART3          '2008-10-01'        '2008-12-31'
PART0          '2008-01-01'        '2008-03-31'

 4 record(s) selected.

/* 檢查完整性 */

set integrity for day_list immediate checked
DB20000I The SQL command completed successfully.

/* 檢查總筆數,因為 part0 的資料被清掉了,所以已經不存在第一季的日期 */

select count(*) from day_list

1
-----------
     275

  1 record(s) selected.

/* attach 之後 tab_reuse0 馬上被 drop 掉 */

select * from tab_reuse0
SQL0204N "DB2ADMIN.TAB_REUSE0" is an undefined name. SQLSTATE=42704

/* 測試使用一般的 table 是不是也能 attach 上去 */

create table day_list_2007Q4 ( dt date ) in userspace1
DB20000I The SQL command completed successfully.

/* 新增一筆日期資料 */

insert into day_list_2007q4 values ('2007-12-31')
DB20000I The SQL command completed successfully.

/* 把剛建立的 table attach 上去並檢查完整性 */

alter table day_list attach partition part2007q4 starting '2007-10-01' ending '2007-12-31' from day_list_2007q4
SQL3601W The statement caused one or more tables to automatically be placed
in the Set Integrity Pending state. SQLSTATE=01586

set integrity for day_list immediate checked
DB20000I The SQL command completed successfully.

/* attach 之後 day_list_2007q4 就被drop掉了 */

select * from day_list_2007q4
SQL0204N "DB2ADMIN.DAY_LIST_2007Q4" is an undefined name. SQLSTATE=42704

/* 檢查資料是否已加入 */

select count(*) from day_list

1
-----------
     276

 1 record(s) selected.

/* 從 SYSTEM TABLE 看 Partition */

select datapartitionname,datapartitionid,lowvalue,highvalue
from sysibm.sysdatapartitions
where tabname = 'DAY_LIST'

PARTITIONNAME     LOWVALUE          HIGHVALUE
---------------------- ------------------------ -------------------------
PART1          '2008-04-01'        '2008-07-01'
PART2          '2008-07-01'        '2008-10-01'
PART3          '2008-10-01'        '2008-12-31'
PART2007Q4       '2007-10-01'        '2007-12-31'
PART0          '2008-01-01'        '2008-03-31'

 5 record(s) selected.

2008年9月7日 星期日

Global variable and federated stored procedure using DB2 9


/*
  使用 DB2 9 的新功能(global variable / federated stored procedure):
  1) create global variable、Materialized Query Table、stored procedure
  2) update dbm cfg 將 FEDERATED 設為YES
  3) create another database: ORIONDB
  4) create wrapper、server、federated stored procedure
*/

-- 在 database SAMPLE 上建立 global variable

connect to sample

  資料庫連線資訊

 資料庫伺服器     = DB2/NT 9.5.0
 SQL 授權 ID     = ORION
 本地資料庫別名    = SAMPLE

-- 建立一個 global variable:startdate 預設值 20080908

create variable startdate integer default 20080908

-- 分別建立一個 table、MQT、stored procedure

create table test
(
  col1 integer,
  col2 varchar(2)
) in userspace1;

-- MQT 裡使用 global variable: startdate

create table mqt_test as
(
  select * from test where col1 >= startdate
) data initially deferred refresh deferred in userspace1;

-- 建立 stored procedure: SP_TEST 來新增 Table test

create procedure SP_TEST(in dt integer,
              in str varchar(2))
specific SP_TEST
language sql
begin
    insert into test values (dt,str);
    commit;
end

-- 新增資料至 test

CALL SP_TEST(20080101,'AA');

  傳回狀態 = 0

CALL SP_TEST(20080105,'BB');

  傳回狀態 = 0

CALL SP_TEST(20081005,'CC');

  傳回狀態 = 0

-- Refresh mqt table

refresh table mqt_test

DB20000I SQL 指令已順利完成。

-- 讀取 mqt table

select * from mqt_test

COL1     COL2
----------- ----
20081005   CC

已選取 1 個記錄。

-- 將 FEDERATED 設為YES

db2 update dbm cfg using FEDERATED YES

db2stop

db2start

-- CREATE DATABASE ORIONDB

create database oriondb on 'c:\' using codeset UTF-8 TERRITORY TW COLLATE using SYSTEM

DB20000I CREATE DATABASE 指令已順利完成。


-- 使用控制中心(db2cc)
-- 選擇資料庫ORIONDB。
-- 如圖,所建Wrapper名稱為WINDB,所建Server名稱為SAMPLE
-- 在聯合儲存程序中,將剛在SAMPLE資料庫建的SP_TEST新增進來



-- 建立 federated stored procedure 語法大致如下:

CREATE PROCEDURE ORION.SP_TEST SOURCE ORION.SP_TEST NUMBER OF PARAMETERS 2 FOR SERVER SAMPLE;


--新增儲存程序時,DB2 會自動為 SAMPLE 裡的 SYSWSIIDB2UDB_ROUTINES 建一個 NICKNAME 進來


-- 在 DB ORIONDB 呼叫 SAMPLE 的 SP_TEST

call sp_test(20080918,'gg')

  傳回狀態 = 0

-- 回到 DB SAMPLE 去檢查

connect to sample

  資料庫連線資訊

 資料庫伺服器    = DB2/NT 9.5.0
 SQL 授權 ID    = ORION
 本地資料庫別名   = SAMPLE

select * from test

COL1      COL2
-------------- ----
20080101    AA
20080105    BB
20081005    CC
20080918    gg

已選取 4 個記錄。

-- REFRESH MQT TABLE

refresh table mqt_test

DB20000I SQL 指令已順利完成。

select * from mqt_test

COL1      COL2
-------------- ----
20081005    CC
20080918    gg

已選取 2 個記錄。

-- 將 global variable startdate 值改為 20071231

set startdate = 20071231

DB20000I SQL 指令已順利完成。

-- REFRESH MQT TABLE

refresh table mqt_test

DB20000I SQL 指令已順利完成。

select * from mqt_test

COL1       COL2
-------------- ------
20080101     AA
20080105     BB
20081005     CC
20080918     gg

已選取 4 個記錄。

2008年9月5日 星期五

DB2 XML full-text search using NSE


/*
  1)Download/Install Net Search Extender and set variable
  2)Create table and load xml data
  3)db2text start/Enable for text
  4)create index for text
  5)update index
  6)Search Text with function Contain()
  7)db2text stop
*/



-- DB2 是透過 Net Search Extender 對 XML 做 full-text search
-- 先到 IBM 官網去 download Net Search Extender,我的版本是9.5
-- 安裝好之後,先去設定環境變數 DB2DBDFT


直接在 CLP 使用 SET 或
「控制台」→「系統」→「進階」→「環境變數」新增系統變數 DB2DBDFT 並且將值給定為使用的 Database 名稱即可,ex: SAMPLE


※ 不設定的話,會一直出現 CTE0139 環境變數 "DB2DBDFT" 尚未設定。
※ 設定好之後,可以不必下connect database,由 db2text 內部直接做掉。


-- 建立一個測試的 table:ARCHAEOLOGY 來存放考古新聞

CREATE TABLE ARCHAEOLOGY
(
   SNO     INTEGER not null primary key,
   NEWSDATE  CHAR(8),
   NEWS    XML
) IN USERSPACE1;

-- XML 的 layout:

< News >
 < Headline >新聞標題< /Headline >
 < Reporter >記者< /Reporter >
 < Venue >事件發生地點< /Venue >
 < NewAgency >新聞社< /NewAgency > 
 < PublishDate >新聞發布時間< /PublishDate >
 < Content >新聞內容< /Content >
< /News >

-- 抓張圖看一下範例:




-- 直接將我自己準備的 16 則新聞以 xml 的格式儲存
-- 並做一個archaeology.del 檔,內容如下:


1,20070309,< XDS FIL='20070309_1.xml'/ >
2,20070402,< XDS FIL='20070402_1.xml'/ >
3,20070711,< XDS FIL='20070711_1.xml'/ >
4,20070712,< XDS FIL='20070712_1.xml'/ >
5,20070713,< XDS FIL='20070713_1.xml'/ >
6,20070716,< XDS FIL='20070716_1.xml'/ >
7,20070719,< XDS FIL='20070719.xml'/ >
8,20070724,< XDS FIL='20070724_2.xml'/ >
9,20070725,< XDS FIL='20070725_2.xml'/ >
10,20070727,< XDS FIL='20070727_1.xml'/ >
11,20070801,< XDS FIL='20070801_1.xml'/ >
12,20070806,< XDS FIL='20070806_1.xml'/ >
13,20070813,< XDS FIL='20070813_1.xml'/ >
14,20070814,< XDS FIL='20070814_1.xml'/ >
15,20070821,< XDS FIL='20070821_2.xml'/ >
16,20080903,< XDS FIL='20080903_1.xml'/ >

-- import 進去

import from archaeology.del of del xml from c:/ insert into archaeology

-- 用 db2text 將 Net Start Extender 叫起來

db2text start

-- 讓 NSE 對 Database SAMPLE 做 text search

db2text enable database for text connect to sample

-- 用 db2text 對 table archaeology 建 index

db2text create index archaeology_idx for text on archaeology(news)

-- 對 index 做 sync

db2text update index archaeology_idx for text


-- 使用Contain()來找資料
-- 1) 用 like 的方式從整個 xml 裡每一個 element 找包含 Alexan 字眼的文章並將新聞標題列出來


select xmlquery('$ns//Headline' passing news as "ns")
from archaeology
where contains(news,'"Alexan%"') = 1;

-- 結果找到亞歷山大大帝與有關亞歷山卓城的新聞


< Headline >Alexander the Great Conquered City via Sunken Sandbar< /Headline >
< Headline >Hidden City Found Beneath Alexandria< /Headline >
< Headline >Ancient "Lost" City's Remains Found Under Alexandria's Waters< /Headline >

   已選取 3 個記錄。


-- 2) 從整個 xml 裡每一個 element 找包含 Tyre 字眼的文章並將新聞標題列出來


select xmlquery('$ns//Headline' passing news as "ns")
from archaeology
where contains(news,'"Tyre"') = 1;

-- 結果在新聞內容中找到亞歷山大大帝征服推羅古城的新聞


< Headline >Alexander the Great Conquered City via Sunken Sandbar< /Headline >

   已選取 1 個記錄。


-- 找包含 the 這個字的有多少新聞

select count(*)
from archaeology
where contains(news,'"the"') = 1;

-- 結果是全部筆數

1
-----------
     16

   已選取 1 個記錄。


-- 再轉一筆今天的新聞進去
-- a1.del 內如如下


17,20080905,< XDS FIL='20080905.xml' / >

-- import

import from a1.del of del xml from c:\ insert into archaeology;

-- 看一下 archaeology 總筆數

select count(*) from archaeology;

1
-----------
     17

   已選取 1 個記錄。

-- 再找找看包含 the 這個字的有多少新聞
--(20080905.xml確定包含 "the" 這個字)


select count(*)
from archaeology
where contains(news,'"the"') = 1;

-- 結果還是 16 筆

1
-----------
     16

   已選取 1 個記錄。

-- 原因是 index 要做 sync

db2text update index archaeology_idx for text

-- 再找找看包含 the 這個字的有多少新聞

select count(*)
from archaeology
where contains(news,'"the"') = 1;

-- 結果就是 17 筆了

1
-----------
     17

   已選取 1 個記錄。

-- 將 db2text 服務關閉

db2text stop
CTE0001 作業順利完成。

2008年9月2日 星期二

can't find db2diag.log - DB2 Express-C v9.5


安裝好 DB2 Express-C v9.5 之後,我發現在 Program File\IBM\SQLLIB\ 下的資料夾數目好像少了點。
心想反正是新的版本,多多少少也做了些修改,因此沒再細查。
今天突然想檢查一下 db2diag.log,看看安裝後的這幾天裡,DB 有沒有什麼錯誤訊息。才發現以往那個有instance name的路徑居然不見了?
就上了 IBM 官網去 download Freebook:GettingStartedwithDB2Express-C_V95-en.pdf

找了db2diag.log的部份,明明就是這樣寫著:

On Windows, the db2diag.log is located by default under th directory:

C:\Program Files\IBM\sqllib\< instance name >\db2diag.log

ㄟ... 可是,我怎麼就是沒有這個 instance name 是 DB2 的路徑呢?

搞半天,原來是死到 C:\Documents and Settings\All Users\Application Data\IBM\DB2\DB2COPY1 這裡去了~



--先檢查一下DIAGPATH的設定值

C:\>db2 get dbm cfg

         資料庫管理程式配置

   節點類型 = 具有本地及遠端用戶端的資料庫伺服器

 資料庫管理程式配置版次             = 0x0c00

 開啟檔案的最大總數       (MAXTOTFILOP) = 16000
 CPU 速度 (千分之一秒/指令)   (CPUSPEED) = 3.345772e-007

 並行作用中資料庫的最大數目        (NUMDB) = 8
 聯合資料庫系統支援          (FEDERATED) = NO
 交易處理器監視器名稱         (TP_MON_NAME) =

 預設記帳帳戶             (DFT_ACCOUNT_STR) =

 Java Development Kit 安裝路徑  (JDK_PATH) = C:\Program Files\IBM\SQLLIB\java\jdk

 診斷錯誤擷取層次          (DIAGLEVEL) = 3
 通知層次              (NOTIFYLEVEL) = 3
 診斷資料目錄路徑          (DIAGPATH) =

 預設資料庫監視器開關
  緩衝池              (DFT_MON_BUFPOOL) = OFF
  ‧
  ‧
  ‧
  ‧

-- DIAGPATH沒設定,再去看DB2INSTPROF

C:\>db2set -all

[i] DB2INSTPROF=C:\Documents and Settings\All Users\Application Data\IBM\DB2\DB2COPY1

-- 果然就在這個地方找到我要的db2diag.log,真機車~

pureXML (II) using DB2 9


/*
  1) register xmlschema
  2) check TARGETNAMESPACE,SCHEMALOCATION
  3) create table with xml datatype
  4) select with explicit validate using target namespace and schema location
  5) insert with explicit validate using target namespace and schema location
*/



-- 做一個xsd,並且指定target namespace
-- 存成 ex: c:\region2.xsd


< ?xml version="1.0"? >
< xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       targetNamespace="http://localhost/region"
       xmlns:r2="http://localhost/region" >
< xsd:element name="region2" >
< xsd:complexType >
< xsd:sequence >
< xsd:element name="regno" type="xsd:string" / >
< xsd:element name="regename" type="xsd:string" / >
< xsd:element name="regcname" type="xsd:string" / >
< /xsd:sequence >
< /xsd:complexType >
< /xsd:element >
< /xsd:schema >


-- register xmlschema
-- 給定schemalocation為http://localhost/region/region2.xsd


register xmlschema 'http://localhost/region/region2.xsd' from c:\region2.xsd as xsd_region2 complete;


-- 從system table: syscat.xsrobjects裡檢查是否已註冊成功
-- check一下 targetnamespace 與 schemalocation 這兩個欄位


select targetnamespace,schemalocation
from  syscat.xsrobjects
where objectname = 'XSD_REGION2';

TARGETNAMESPACE      SCHEMALOCATION
------------------------ ---------------------------------------------------
http://localhost/region http://localhost/region/region2.xsd

  已選取 1 個記錄。



-- 手動建立一個table。
-- 這與oracle不同,oracle在xsd裡的xdb註明xml table後,oracle會自動產生


create table region2
(
    id      integer,
    regioninfo  xml
);


-- 新增前先select並寫好想要使用validate的方式,
-- 這裡使用uri (targetnamespace與schemalocation)來執行validate。
-- (pureXML(I) using DB2 9 指定的是 xmlschema ID來做validate)。


select xmlvalidate(xmlparse(document
      '< ?xml version="1.0" encoding="UTF-8"? >
      < r2:region2 xmlns:r2="http://localhost/region" >
      < regno >1< /regno >
      < regename >Northern< /regename >
      < regcname >北區< /regcname >
      < /r2:region2 >' preserve whitespace)
    according to xmlschema uri 'http://localhost/region'
    location 'http://localhost/region/region2.xsd'
)
from  sysibm.sysdummy1;

-- 得到以下結果,並且未出現錯誤訊息

< r2:region2 xmlns:r2="http://localhost/region" >< regno >1< /regno >< regename >Northern< /regename >< regcname >北區< /regcname >< /r2:region2 >

-- 新增xml data至region2

insert into region2 values
(1,xmlvalidate(xmlparse(document
      '< ?xml version="1.0" encoding="UTF-8"? >
      < r2:region2 xmlns:r2="http://localhost/region" >
      < regno >1< /regno >
      < regename >Northern< /regename>
      < regcname >北區< /regcname>
      < /r2:region2 >' preserve whitespace
     ) according to xmlschema uri 'http://localhost/region'
      location 'http://localhost/region/region2.xsd'));

-- 檢查是否資料新增至region2

select count(*) from region2

1
-----------
      1

  已選取 1 個記錄。

2008年9月1日 星期一

pureXML (I) using DB2 9


/*
  1) register xmlschema
  2) create table with xml datatype
  3) import xml and explicit validate using SQL identifiers as well
*/


-- 首先先將xsd寫好如下 ex:region4.xsd
-- ※ 裡面包含地區代碼/地區英文名稱/地區中文名稱


< ?xml version="1.0"? >
< xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
< xsd:element name="region4" >
< xsd:complexType >
< xsd:sequence >
< xsd:element name="regno" type="xsd:string" / >
< xsd:element name="regename" type="xsd:string" / >
< xsd:element name="regcname" type="xsd:string" / >
< /xsd:sequence >
< /xsd:complexType >
< /xsd:element >
< /xsd:schema >


-- 將xmlschema register進去
-- http://localhost/region4是我給定的xmlschema uri
-- xsd_region4 是這個xmlschema的ID
-- 可下sql檢查是否register成功:
-- select * from syscat.xsrobjects where objectname = 'XSD_REGION4'


register xmlschema 'http://localhost/region4' from c:\region4.xsd as xsd_region4 complete

-- 建立一個有XML資料型態的TABLE

create table region4
(
  id      integer not null,
  regioninfo xml,
  constraint pk_region4 primary key (id)
);


-- 建好之後處理import要使用的檔案
-- 隨便舉例,import 三個xml檔案
-- 1.xml:


< ?xml version="1.0" encoding="UTF-8"? >
< region4 >
< regno >1< /regno >
< regename >Northern< /regename >
< regcname >北區< /regcname >
< /region4 >


-- 2.xml:


< ?xml version="1.0" encoding="UTF-8"? >
< region4 >
< regno >2< /regno >
< regename >Central< /regename >
< regcname >中區< /regcname >
< /region4 >


-- 3.xml:


< ?xml version="1.0" encoding="UTF-8"? >
< region4 >
< regno >3< /regno >
< regename >Southern< /regename >
< regcname >南區< /regcname >
< /region4 >


-- 準備要import的.del檔案。c:\region4.del
-- 用XDS指定


1,< XDS FIL='1.xml'/ >
2,< XDS FIL='2.xml'/ >
3,< XDS FIL='3.xml'/ >

-- 開始import

import from region4.del of del xml from c:/ xmlvalidate using xds default xsd_region4 insert into region4

-- 看結果

select count(*) from region4

1
---------
     3

  已選取 1 個記錄。

-- 全部都是validated過的資料

select count(*) from region4 where regioninfo is validated

1
---------
     3

  已選取 1 個記錄。