之前是做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 == `