1. 程式人生 > 其它 >淺析SQL資料型別的隱式轉換與顯式轉換以及隱式轉換可能導致的問題

淺析SQL資料型別的隱式轉換與顯式轉換以及隱式轉換可能導致的問題

一、隱式型別轉換問題

1、隱式型別轉換:

  比如:SELECT 1 + '1';

2、隱式型別轉換的問題:

(1)程式可讀性差,且依賴資料庫的隱式轉換規則,效率差,會增加處理時間;且如果資料庫升級,則程式可能無法正確執行;

(2)有可能會導致索引失效;

(3)有可能會導致意想不到的結果;

3、顯式型別轉換:SELECT 1 + CAST('1' AS SIGNED INT);

4、原則:儘量用顯式型別轉換

5、隱式轉換問題示例:

(1)數值型 + 字元型

SELECT 1+'1';           -- 結果:2
SELECT CONCAT('北京',2008);    -- 結果:北京2008
SELECT '北京' + 2008; -- 結果: 可能2008,可能報錯 SELECT 'HELLO ' + 'WORLD!'; -- 結果:可能 0,可能報錯

(2)隱式型別轉換導致索引失效

CREATE TABLE teacher(
teacher_id VARCHAR(50),
teacher_name VARCHAR(50),
id_no VARCHAR(50)
);

CREATE INDEX idx_teacher_id ON teacher(teacher_id);

CREATE TABLE student(
student_id INT,
student_name 
VARCHAR(50), teacher_id INT ); CREATE INDEX idx_teacher_id ON student(teacher_id); SELECT * FROM student a INNER JOIN teacher b ON a.teacher_id = b.teacher_id; -- 此時不會走索引,因為在teacher表中,teacher_id是varchar型別,而student表中teacher_id是int型別, -- 會做隱式型別轉換,把varchar轉為int型別;

(3)隱式型別轉換導致意想不到的結果

SELECT 10/4;       --
結果:2 解決:可以把分母分子乘以1.00,再運算 SELECT COUNT(*) FROM table1; -- count返回的是int型別,如果表中資料量超過count出來的數,就報錯 -- 解決:在count(*) 外面cast轉換一下,轉換為能儲存結果的型別
SELECT COUNT(*) FROM teacher WHERE teacher_name = 0;
-- 為什麼不是等價於:
SELECT COUNT(*) FROM teacher WHERE teacher_name= '0';

-- 因為隱式型別轉換時,轉的是左邊而不是右邊;

-- 以下語句會返回兩條資訊,而不是一條,因為530102192005080114這串數字,已經超過了int型別的範圍,
-- 超過了int型別的範圍就會轉為float型別,等號兩邊都轉為float型別,會丟精度,也就是最後一位數丟了,剩下的就相等了,就全返回了;

SELECT COUNT(*) FROM teacher WHERE id_no = 530102192005080114;
-- 等價於:
SELECT COUNT(*) FROM teacher WHERE 
CAST(id_no AS DECIMAL) = CAST(530102192005080114 AS DECIMAL);

-- 在查詢時把530102192005080114加上單引號就可以了;

二、SQL 資料型別轉換

  資料型別轉換分為隱式轉換和顯式轉換。

1、顯式轉換:顧名思義就是使用函式進行資料型別轉化,如cast、convert

2、隱式轉換問題

-- 例子1
SELECT 1+1’ –返回值為2

-- 例子 2
SELECT
CASE
WHEN 1 > 1 THEN 10
WHEN 1 = 1 THEN10WHEN 1 < 1 THEN 10.2
END    -- 返回值為10.2

-- 例子3
SELECT
CASE
WHEN 1 > 1 THEN 10
WHEN 1 = 1 THEN ‘abc’
WHEN 1 < 1 THEN 10.2
END     -- 語法錯誤 

  在第一個例子中,'1' 被轉換為 int 的 1 ;

  在第二個例子中,不管那個後面的條件成立,結果都被轉換為decima;

  第三個例子由於‘ab’轉換為decimal失敗,所以報錯。

  為什麼呢? —— 這是因為 sql server 中有多個數據型別在一個表示式中時會存在隱式的轉換,各個資料型別的優先順序如下:

1、使用者定義資料型別(最高)
2、sql_variant
3、xml
4datetime
5smalldatetime
6float
7real
8decimal
9money
10smallmoney
11bigint
12int
13smallint
14tinyint
15bit
16ntext
17text
18image
19timestamp
20uniqueidentifier
21nvarchar(包括 nvarchar(max))
22nchar
23varchar (包括 varchar(max))
24char
25varbinary(包括 varbinary(max))
26binary(最低) 

3、詳細見:資料型別優先順序 (Transact-SQL) —— https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2005/ms190309(v=sql.90)?redirectedfrom=MSDN

  當兩個不同資料型別的表示式用運算子組合後,資料型別優先順序規則指定將優先順序較低的資料型別轉換為優先順序較高的資料型別。 如果此轉換不是所支援的隱式轉換,則返回錯誤。 當兩個運算元表示式具有相同的資料型別時,運算的結果便為該資料型別。

  這裡有一篇文章也說了這個 case when 裡的隱式轉換導致的問題,可以看下:《SQL Server有意思的資料型別隱式轉換問題