oracle與infomix異同點

皇家救星發表於2018-12-22

  之前是做oracle資料庫應用開發的,現在工作用的是informix,特別不習慣。用了一段時間後才慢慢適應,最近做系統升級,把informix換成oracle資料庫。順便整理了一下informix與oracle區別,希望對各位有用。

差異點

oracle

infomix

update多列

update set c1 = `c1`, c2 = `c2`

update set (c1, c2) = (`c1`, `c2`)

命令列操作工具

sqlplus

dbaccess

插入欄位內容超長

插入失敗,報錯

超長部分可能被截斷

對正在修改的表進行查詢

無影響

如果不走索引,會引起“Could not position within a table ”問題

需要在查詢前設定

set lock mode to wait n;(n是等待秒數)

檢視資料庫使用者下所有表名

user_tables

sysmaster.systables

匯出庫表資料

自己寫程式或者指令碼

load

匯入庫表資料

sqlldr

unload

物件名長度限制

32個字元

沒查過,但遠超過32

空字串

沒有空字串,只有NULL,“與NULL等價

“與NULL是兩個不同的東西,所以字元設定not null也可以插入“

rowid

全域性不同

每個表都是從1開始

rownum

無,但支援select [skip] first n

日期date型別

需要比較顯示地使用to_date和to_char函式互轉。如果沒寫系統會自動進行隱式轉換。

直接使用類似日期的字串

保留字

resource、union、level、mode、

start 這些都是oracle保留字,不能用於庫表或欄位名

這些不是保留字(應該還有其它的保留字區別,這裡只整理我們專案碰到的)

yestorday current、year、today、day、month、weekday

不支援,需要使用sysdate-1,sysdate,add_year(sysdate, 1)等寫法

支援

varchar

最長4000,叫varchar2

最長256

char

自動補全空格

自動補全空格,但查詢時會自動刪除這些空格,所以對於使用者來說感覺跟不補空格一樣

字串擷取

只支援substr

支援substr或者欄位名[first, n]的寫法,如res[1, 2]

呼叫儲存過程

直接呼叫儲存過程名稱

call 或者是execute procedure

call 呼叫如果有錯誤只是會提示籠統錯誤。而execute則是提示具體錯誤

number型別

decimal

dual

沒有,但是可以自己建立一張

儲存查詢結果

支援create table as select

insert into select

只支援insert into select

統計更新

dbms_stat .gather_table_stats

update statistcs

大事務(如一個語句更新幾萬條資料)

對資料庫效能影響比較小

對資料庫效能影響比較大

連線字串

一樣,可以使用||

一樣,可以使用||

庫表連線

一樣,支援=寫法

一樣,支援=寫法

truncate

支援

支援

merge

支援

支援

另外,在專案資料遷移過程中,我總結了unload匯出資料特點:

 

1 char型別匯出時,會自動去除尾部空格

2 如果varchar型別欄位的值是null,則匯出結果是空字串,但如果值是“,匯出結果是斜槓空格(” “)

3 char型別欄位如果值是“,匯出結果是空格(” “)

4 unload匯出時可以指定欄位分隔符delimiter,如果欄位值本身包含delimiter,則會匯出成delimiter

5 如果欄位值含有“,則會匯出成雙斜槓(”\”)

 

我寫了一個將informix用unload匯出來的文字裝載回oracle的程式,大家有需要可以看看(操作oracle是用的otl,所以理論上也支援匯入資料到informix,不過沒測試過)

load_from_file.cc

 

//檔案裝載程式
#ifndef WIN32
//程式裡面使用了get_rpc,用以統計成功入庫的記錄
//根據otl文件描述,在入庫出現異常時,get_rpc在odbc和oci模式下返回結果有較大差異
//odbc模式下入庫異常時get_rpc返回0,oci下則可以正確返回
#define OTL_ORA11G_R2
//#define OTL_ODBC_UNIX
//#define OTL_INFORMIX_CLI
#else
//#define OTL_ODBC  
#define OTL_ORA11G_R2
#ifndef snprintf
#define snprintf _snprintf
#endif
#endif

#define OTL_STREAM_READ_ITERATOR_ON //在沒有返回資料的情況下丟擲異常
#define OTL_PARANOID_EOF
#define OTL_STL


#include <string>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "otlv4.h"

using namespace std;
#define MAX_COLUMN_LEN 2048
#define MAX_LINE_LEN 8092

//是否檢查列裡面有空行記錄 如果不定義這個巨集則不主動檢查
#define CHECK_NULL_COLUMN 0

extern "C" {
    //獲取資料庫登入資訊
    int GetODBCInfo(char *dbname,char *dbusername,char *dbpasswd);
}

//函式出口比較多是,釋放資源偷懶類
template<typename T, typename FUN>
class CSimpleRelease
{
public:
    CSimpleRelease(T *pResourse, FUN releaseFunc):m_pResourse(pResourse), m_releaseFunc(releaseFunc)
    {

    }

    ~CSimpleRelease()
    {
        m_releaseFunc(m_pResourse);
    }

public:
    T *m_pResourse;
    FUN m_releaseFunc;
};

class ColumnInfo
{
public:
    ColumnInfo()
    {
        columnTypes = NULL;
        columnCnt = 0;
    }

    ~ColumnInfo()
    {
        if (columnTypes != NULL)
        {
            delete []columnTypes;
            columnTypes = NULL;
        }
    }

    int columnCnt;
    int *columnTypes; //0字串型別,1時間型別

#ifdef CHECK_NULL_COLUMN
    vector<string> vecName;
    vector<int> vecNullable;
#endif

private:
    ColumnInfo(const ColumnInfo& other)
    {
        //不讓使用者拷貝賦值
    }


    ColumnInfo& operator =(const ColumnInfo& other)
    {
        //不讓使用者拷貝賦值
    }
};

//使用select * from table_name返回的列資訊拼接成insert sql
bool getTabInfo(const char *tableName, otl_connect& db, string& insertSql, ColumnInfo &columnInfo)
{
    insertSql = string("insert into ") + tableName;
    string valuesSql = " values(";

    char column_type_format_str[64];

    snprintf(column_type_format_str, sizeof(column_type_format_str), ":c%%d<char[%d]>, ", MAX_COLUMN_LEN);
    char column_type_format_date[] = ":c%d<timestamp>, ";

    bool bRet = true;
    otl_stream cur;
    int nColumnCnt = 0;
    otl_column_desc *column_des = NULL;
    try
    {
        string selectSql = string("select * from ") + tableName;
        cur.open(1, selectSql.c_str(), db);

        column_des = cur.describe_select(nColumnCnt);

    }
    catch(otl_exception& p)
    {
        cerr << "database err:" << endl;
        cerr << "stm_text = " << p.stm_text << endl;
        cerr << "msg = " << p.msg << endl;
        cerr << "var_info = " << p.var_info << endl;
        bRet = false;
    }

    if (!bRet || nColumnCnt <= 0 || column_des == NULL)
    {
        cerr << "errmsg=獲取庫表列資訊出錯" << endl;
        return false;
    }

    columnInfo.columnCnt = nColumnCnt;
    columnInfo.columnTypes = new int[nColumnCnt];
    assert(columnInfo.columnTypes != NULL);

    //對於大多數資料庫來說,資料型別和字串型別在輸入時沒區別
    //舉例insert into demo(num_int, num_double, str) values(`1`, `1.1`, `1`)
    for (int i = 0; i < nColumnCnt; i++)
    {
#ifdef CHECK_NULL_COLUMN
        columnInfo.vecName.push_back(column_des[i].name);
        columnInfo.vecNullable.push_back(column_des[i].nullok);
#endif
        const char *pColumnTypeFormat = NULL;
        //這裡只需要區分是否時間欄位即可
        switch (column_des[i].otl_var_dbtype) {
        case otl_var_timestamp:
        case otl_var_db2time:
        case otl_var_db2date:
            columnInfo.columnTypes[i] = 1;
            pColumnTypeFormat = column_type_format_date;
            break;

        default:
            columnInfo.columnTypes[i] = 0;
            pColumnTypeFormat = column_type_format_str;
            break;
        }

        char buffer[256];
        snprintf(buffer, sizeof(buffer), pColumnTypeFormat, i);
        valuesSql += buffer;
    }
    column_des = NULL;
    cur.close();

    //去掉末尾的", "
    valuesSql.resize(valuesSql.length() - 2);

    insertSql += valuesSql + ")";
    return true;
}

bool connectDataBase(otl_connect &db)
{
    char  P1[128] = {0}, P2[128] = {0}, P3[128] = {0};
    int iRet = GetODBCInfo(P1,P2,P3);
    if(iRet != 0) 
    {
        cout << "GetODBCInfo err" << endl;        
    }

    /*
    cout << "P1 = " << P1 << endl;
    cout << "P2 = " << P2 << endl;
    cout << "P3 = " << P3 << endl;
    */

    bool bRet = true;
    try
    {
        otl_connect::otl_initialize(1); // initialize OCI environment 多執行緒設定1
        char connect_str[128];
        snprintf(connect_str, sizeof(connect_str), "%s/%s@%s", P2, P3, P1); 
        db.rlogon(connect_str, 0);
    }
    catch(otl_exception& p)
    {
        cerr << "database err:" << endl;
        cerr << "stm_text = " << p.stm_text << endl;
        cerr << "msg = " << p.msg << endl;
        cerr << "var_info = " << p.var_info << endl;
        bRet = false;
    }

    return bRet;
}

//在字串中查詢一個位元組,忽略中文(有些特殊中文編碼正好有豎線)
char *strchrEngOnly(char *str, char ch)
{
    while (*str)
    {
        //中文字元佔兩個位元組,第一個位元組第一位是1
        if (0x80 & *str)
        {
            str++;
            //一般不會有這樣的情況 防異常
            if (*str == `

相關文章