CodeGym /課程 /SQL SELF /資料型別的比較與轉換

資料型別的比較與轉換

SQL SELF
等級 16 , 課堂 3
開放

為什麼我們要搞這些比較和型別轉換?想像一下,你的資料表裡有個字串 "42",但你想拿它跟數字 42 比較。乍看之下好像一樣,但對資料庫來說,這兩個東西完全不同。PostgreSQL 不會自動猜你想幹嘛。如果你不懂它怎麼比較不同型別的值,結果可能會很奇怪,甚至直接報錯。

轉換也是一樣。有時候你得把文字變成數字,這樣才能算出到底有多少個東西。反過來,有時候你想把數字漂亮地顯示成字串。或者你想把日期顯示成 "01.01.2025",因為這樣用戶比較習慣。

再舉個例子:你有個精確值存在 NUMERIC,但做科學計算時要用 FLOAT。這種情況下,不明講要轉換是不行的。

好消息是 PostgreSQL 處理這些超級給力。它給你很彈性又直覺的工具。重點是你要知道怎麼用,也不要怕多看一點底層細節。我們就來玩玩看。

資料型別的比較

PostgreSQL 很聰明——如果它看到你在比較 INTEGERNUMERIC,它會自動幫你轉成一樣的型別再比較。這沒問題,因為兩個都是數字。

但如果你想拿字串跟布林值比(TEXTBOOLEAN),資料庫就會一臉問號,不知道你想幹嘛。這兩種型別本質完全不同,PostgreSQL 只會直接報錯。同樣地,如果你想把 "42" 這個字串跟數字 42 比較,沒明講要轉換,也會出錯。

實際上會長這樣,這個例子會報錯:

SELECT '42' = 42; -- 錯誤!字串和數字沒轉換不能直接比

這樣寫才會正常:

SELECT '42'::INTEGER = 42; -- TRUE

這裡我們直接跟它說:「拜託,先把 '42' 變成數字」。這就是 ::型別 這個語法的用法,之前有提過。PostgreSQL 喜歡你跟它講清楚。

數值型別的比較

數值型別(INTEGERNUMERICREAL)通常彼此相容,所以你可以直接比較,沒什麼難度:

SELECT 42 = 42.0; -- TRUE
SELECT 42::REAL = 42.0; -- TRUE
SELECT 42.0::NUMERIC = 42; -- TRUE

但要小心浮點數(REAL)。因為精度有限,這種數字有時候會出現怪現象。例如:

SELECT 0.1 + 0.2 = 0.3; -- FALSE

這是不是最有名的程式謎題?這裡比較會回傳 FALSE,因為電腦記憶體裡存小數有特殊方式。

文字型別的比較

處理文字型別時,你可以比較 CHARVARCHARTEXT,因為 PostgreSQL 會自動幫你轉成相容型別:

SELECT 'Hello' = 'Hello'::TEXT; -- TRUE
SELECT 'World'::CHAR(5) = 'World'::VARCHAR; -- TRUE

注意 CHAR(n) 的長度:如果字串比指定長度短,PostgreSQL 會自動補空白。

資料型別的轉換

PostgreSQL 有幾種方式可以轉換資料型別。我們來看兩個主要方法:

方法一:明確轉換(CAST

CAST 運算子可以讓你指定怎麼把一種型別轉成另一種。像這樣:

SELECT CAST('42' AS INTEGER); -- 把字串 '42' 轉成數字 42

這種寫法特別適合讓 SQL 程式碼更好讀。

方法二:簡寫(::

PostgreSQL 也有另一種轉型語法,就是用 ::。這跟上面一樣,只是更短:

SELECT '42'::INTEGER; -- 跟 CAST('42' AS INTEGER) 一樣

自動轉換

很多時候 PostgreSQL 會自動幫你轉型。例如在字串欄位裡用數字:

SELECT '42' = 42::TEXT; -- TRUE

不過,太依賴自動轉換不一定安全,因為其他開發者可能會被搞混。像日期和字串這種,最好還是明講要轉換。

各種型別轉換範例

數字轉成文字

有時候你會想把數字轉成文字(比如要組訊息):

SELECT 42::TEXT; -- 把數字 42 轉成字串 '42'
SELECT 3.14::TEXT; -- 把數字 3.14 轉成字串 '3.14'

文字轉成數字

如果字串裡是合法的數字,你可以把它轉成數值型別:

SELECT '123'::INTEGER; -- 把字串 '123' 轉成數字 123
SELECT '3.14'::FLOAT;  -- 把字串 '3.14' 轉成數字 3.14

那如果字串根本不能轉呢?比如:

SELECT 'Hello'::INTEGER; -- 錯誤:'Hello' 不能轉成數字

為了避免這種錯誤,你可以用 TRY_CAST()(PostgreSQL 14 以後有)或先檢查資料。

日期和文字互轉

轉換日期時可以用 TO_CHAR()TO_DATE()

SELECT TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD'); -- 把日期轉成字串
SELECT TO_DATE('2023-10-25', 'YYYY-MM-DD'); -- 把字串轉成日期

BOOLEAN 跟文字互轉

布林型別 BOOLEAN 也可以轉成字串:

SELECT TRUE::TEXT; -- 'true'
SELECT FALSE::TEXT; -- 'false'

反過來也可以:

SELECT 'true'::BOOLEAN; -- TRUE
SELECT 'false'::BOOLEAN; -- FALSE

注意像 'yes''no' 這種字串不會自動轉換。

實戰:全部用實例來玩

我們來建個表,示範不同型別的用法:

id number_as_text - TEXT number_as_integer - INTEGER date_as_text - TEXT actual_date - DATE
1 42 42 2023-10-25 2023-10-25
2 3.14 NULL 2023-10-24 NULL
3 Hello 123 NULL NULL

現在來做些轉換操作:

-- 文字轉成數字
SELECT number_as_text::INTEGER FROM data_types_demo WHERE number_as_text = '42';

-- 日期轉成文字
SELECT TO_CHAR(actual_date, 'DD/MM/YYYY') FROM data_types_demo;

-- 字串轉成日期
SELECT TO_DATE(date_as_text, 'YYYY-MM-DD') FROM data_types_demo;

資料轉換常見錯誤

常見錯誤有:

  1. 想把不合格式的資料轉型(比如把 'Hello' 轉成 INTEGER)。
  2. 處理浮點數時遇到四捨五入或精度問題。
  3. 轉換日期時格式用錯。

為了避免出錯,建議:

  • 轉換前一定要先檢查資料。
  • 用錯誤處理函數(TRY_CASTCASE)。
  • 轉換日期時一定要明確指定格式。
-- 轉換前先檢查資料
SELECT 
    CASE 
        WHEN number_as_text ~ '^\d+$' THEN number_as_text::INTEGER
        ELSE NULL
    END AS safe_integer
FROM data_types_demo;

用這種方式,你的查詢就不怕遇到怪資料啦!

到這裡你已經有基本功可以在 PostgreSQL 裡比較和轉換型別了。剩下就是多練、多玩、多實作。下次課再見囉!

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION