為什麼我們要搞這些比較和型別轉換?想像一下,你的資料表裡有個字串 "42",但你想拿它跟數字 42 比較。乍看之下好像一樣,但對資料庫來說,這兩個東西完全不同。PostgreSQL 不會自動猜你想幹嘛。如果你不懂它怎麼比較不同型別的值,結果可能會很奇怪,甚至直接報錯。
轉換也是一樣。有時候你得把文字變成數字,這樣才能算出到底有多少個東西。反過來,有時候你想把數字漂亮地顯示成字串。或者你想把日期顯示成 "01.01.2025",因為這樣用戶比較習慣。
再舉個例子:你有個精確值存在 NUMERIC,但做科學計算時要用 FLOAT。這種情況下,不明講要轉換是不行的。
好消息是 PostgreSQL 處理這些超級給力。它給你很彈性又直覺的工具。重點是你要知道怎麼用,也不要怕多看一點底層細節。我們就來玩玩看。
資料型別的比較
PostgreSQL 很聰明——如果它看到你在比較 INTEGER 跟 NUMERIC,它會自動幫你轉成一樣的型別再比較。這沒問題,因為兩個都是數字。
但如果你想拿字串跟布林值比(TEXT 跟 BOOLEAN),資料庫就會一臉問號,不知道你想幹嘛。這兩種型別本質完全不同,PostgreSQL 只會直接報錯。同樣地,如果你想把 "42" 這個字串跟數字 42 比較,沒明講要轉換,也會出錯。
實際上會長這樣,這個例子會報錯:
SELECT '42' = 42; -- 錯誤!字串和數字沒轉換不能直接比
這樣寫才會正常:
SELECT '42'::INTEGER = 42; -- TRUE
這裡我們直接跟它說:「拜託,先把 '42' 變成數字」。這就是 ::型別 這個語法的用法,之前有提過。PostgreSQL 喜歡你跟它講清楚。
數值型別的比較
數值型別(INTEGER、NUMERIC、REAL)通常彼此相容,所以你可以直接比較,沒什麼難度:
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,因為電腦記憶體裡存小數有特殊方式。
文字型別的比較
處理文字型別時,你可以比較 CHAR、VARCHAR 跟 TEXT,因為 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;
資料轉換常見錯誤
常見錯誤有:
- 想把不合格式的資料轉型(比如把
'Hello'轉成INTEGER)。 - 處理浮點數時遇到四捨五入或精度問題。
- 轉換日期時格式用錯。
為了避免出錯,建議:
- 轉換前一定要先檢查資料。
- 用錯誤處理函數(
TRY_CAST或CASE)。 - 轉換日期時一定要明確指定格式。
-- 轉換前先檢查資料
SELECT
CASE
WHEN number_as_text ~ '^\d+$' THEN number_as_text::INTEGER
ELSE NULL
END AS safe_integer
FROM data_types_demo;
用這種方式,你的查詢就不怕遇到怪資料啦!
到這裡你已經有基本功可以在 PostgreSQL 裡比較和轉換型別了。剩下就是多練、多玩、多實作。下次課再見囉!
GO TO FULL VERSION