ORACLE中的隱式資料型別轉換(一)
[i=s] 本帖最後由 wei-xh 於 2013-9-29 10:34 編輯
ORACLE中的隱式資料型別轉換可能有很多你沒留意到的內容。
create table test (id varchar2(100));
create unique index test_id_ind on test(id);
建立了一張表,列id的型別為varchar2,id上有唯一索引。
我們做如下查詢,id的值設定為數字型的1。
SQL> SELECT * FROM test WHERE id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 217508114
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 52 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST | 1 | 52 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("ID")=1)
執行計劃的尾部出現了TO_NUMBER("ID")=1,然後不可避免的執行計劃走了全表掃描。
可能大多數的人都認為ORACLE會採用如下的資料型別轉換:
WHERE id = 1
轉換為
id=to_char(1)
但是實際發生的轉換卻是:
to_number(id)=1
ORACLE在查詢的列上採用函式,導致索引被忽略,可能這點讓你費解,為什麼ORACLE不在查詢條件上採用函式,而在查詢列上使用,難道ORACLE就不關注效率嗎?
不然。
ORACLE當然關注效率,但是ORACLE更多時候更應該尊重SQL所表達的意圖以及返回結果的正確性。
當你發出一個查詢
select * from test where id=1的時候,ORACLE理解的你的意圖是想查詢出ID列轉換為數值後,結果為1的記錄,如果不這樣做,有可能會導致結果的不正確。
當數字以字元型別被儲存的時候,1可以被儲存為‘1’,也可以被儲存為‘001’,‘0000001’等等,看如下實驗:
SQL> insert into test values('1');
1 row created.
SQL> insert into test values('0001');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test where id=1;
ID
---------------------------------
1
0001
select to_number('0000000000001') from dual;
TO_NUMBER('0000000000001')
--------------------------
1
當你發出一個查詢
select * from test where id=1
如果ORACLE自以為是的把你的查詢條件變為id=to_char(1),那麼返回的結果將會不正確:
SQL> select * from test where id=to_char(1);
ID
-----------------------------------
1
丟失了id為0001的記錄
但是你可能會說,不對,這不符合我的預期,我希望返回的只是id為'1'的記錄,既然這樣,那還是請你遵守ORACLE的法則,明確的寫明:id=to_char(1)或者id='1'
還有一點需要注意,隱式轉換過程中,可能出現轉換錯誤:
SQL> select * from test;
ID
----------------------------------------------------------------------------------------------------------------------------------------------------------------
1
0001
insert into test values('xxx');
commit;
SQL> select * from test where id=1;
ERROR:
ORA-01722: invalid number
由於xxx不能被轉換為數字,因此在查詢裡的隱式型別轉換錯誤,導致查詢報錯。
這裡說了隱式轉換的幾個問題,為了規避這些問題,我們應該遵守:
1)如果一個列為數值型的,那就將列設定為數值型,不要設定為varchar2
2)寫查詢條件的時候,請注意列的字元型別,避免型別的隱式轉換,除非這個轉換是你需要的,否則都請顯式的進行轉換。
ORACLE中的隱式資料型別轉換可能有很多你沒留意到的內容。
create table test (id varchar2(100));
create unique index test_id_ind on test(id);
建立了一張表,列id的型別為varchar2,id上有唯一索引。
我們做如下查詢,id的值設定為數字型的1。
SQL> SELECT * FROM test WHERE id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 217508114
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 52 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST | 1 | 52 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("ID")=1)
執行計劃的尾部出現了TO_NUMBER("ID")=1,然後不可避免的執行計劃走了全表掃描。
可能大多數的人都認為ORACLE會採用如下的資料型別轉換:
WHERE id = 1
轉換為
id=to_char(1)
但是實際發生的轉換卻是:
to_number(id)=1
ORACLE在查詢的列上採用函式,導致索引被忽略,可能這點讓你費解,為什麼ORACLE不在查詢條件上採用函式,而在查詢列上使用,難道ORACLE就不關注效率嗎?
不然。
ORACLE當然關注效率,但是ORACLE更多時候更應該尊重SQL所表達的意圖以及返回結果的正確性。
當你發出一個查詢
select * from test where id=1的時候,ORACLE理解的你的意圖是想查詢出ID列轉換為數值後,結果為1的記錄,如果不這樣做,有可能會導致結果的不正確。
當數字以字元型別被儲存的時候,1可以被儲存為‘1’,也可以被儲存為‘001’,‘0000001’等等,看如下實驗:
SQL> insert into test values('1');
1 row created.
SQL> insert into test values('0001');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test where id=1;
ID
---------------------------------
1
0001
select to_number('0000000000001') from dual;
TO_NUMBER('0000000000001')
--------------------------
1
當你發出一個查詢
select * from test where id=1
如果ORACLE自以為是的把你的查詢條件變為id=to_char(1),那麼返回的結果將會不正確:
SQL> select * from test where id=to_char(1);
ID
-----------------------------------
1
丟失了id為0001的記錄
但是你可能會說,不對,這不符合我的預期,我希望返回的只是id為'1'的記錄,既然這樣,那還是請你遵守ORACLE的法則,明確的寫明:id=to_char(1)或者id='1'
還有一點需要注意,隱式轉換過程中,可能出現轉換錯誤:
SQL> select * from test;
ID
----------------------------------------------------------------------------------------------------------------------------------------------------------------
1
0001
insert into test values('xxx');
commit;
SQL> select * from test where id=1;
ERROR:
ORA-01722: invalid number
由於xxx不能被轉換為數字,因此在查詢裡的隱式型別轉換錯誤,導致查詢報錯。
這裡說了隱式轉換的幾個問題,為了規避這些問題,我們應該遵守:
1)如果一個列為數值型的,那就將列設定為數值型,不要設定為varchar2
2)寫查詢條件的時候,請注意列的字元型別,避免型別的隱式轉換,除非這個轉換是你需要的,否則都請顯式的進行轉換。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22034023/viewspace-773574/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料型別的隱式轉換資料型別
- oracle資料型別隱式轉換----- 應急方案Oracle資料型別
- JavaScript 隱式資料型別轉換JavaScript資料型別
- Java資料型別的顯式轉換和隱式轉換Java資料型別
- SQL Server資料庫中的資料型別隱式轉換問題SQLServer資料庫資料型別
- 資料型別隱式轉換導致的阻塞資料型別
- 從Java的型別轉換看MySQL和Oracle中的隱式轉換(二)Java型別MySqlOracle
- 關於隱式資料型別轉換的一些試驗資料型別
- JavaScript隱式型別轉換JavaScript型別
- MySQL 隱式型別轉換MySql型別
- javascript資料型別隱式和顯式轉換詳解JavaScript資料型別
- 欄位的資料型別隱式轉換有關係資料型別
- Oracle隱式型別轉換導致索引失效Oracle型別索引
- javascript 隱式資料型別轉換程式碼例項JavaScript資料型別
- oracle中date資料型別與timestamp資料型別的轉換Oracle資料型別
- C++隱式型別的轉換C++型別
- 有趣的JavaScript隱式型別轉換JavaScript型別
- oracle 資料型別轉換Oracle資料型別
- 淺談Oracle中隱式型別轉換規律和影響Oracle型別
- C語言的隱式型別轉換C語言型別
- JavaScript的隱式型別轉換淺析JavaScript型別
- oracle資料隱式轉換規則Oracle
- javascript中隱私型別轉換JavaScript型別
- C# 隱式型別轉換(轉載)C#型別
- 如何實現隱式型別轉換型別
- 談談 MySQL 隱式型別轉換MySql型別
- C++隱式類型別轉換C++型別
- C++ 隱式類型別轉換C++型別
- 索引失效系列——隱式型別轉換索引型別
- JavaScript隱式型別轉換趣解JavaScript型別
- c++隱式型別轉換存在的陷阱C++型別
- 「譯」JavaScript 的怪癖 1:隱式型別轉換JavaScript型別
- MySQL和Oracle中的隱式轉換MySqlOracle
- 【關於Javascript】--- 隱式型別轉換篇JavaScript型別
- 建構函式定義的隱式型別轉換函式型別
- 從兩個小例子看js中的隱式型別轉換JS型別
- javascript運算中的隱式型別轉換簡單介紹JavaScript型別
- 資料型別,型別轉換資料型別