Tại sao phải quan tâm đến việc so sánh và chuyển đổi kiểu dữ liệu? Hãy tưởng tượng, trong bảng của bạn có một chuỗi "42", còn bạn lại muốn so sánh nó với số 42. Nhìn qua thì giống nhau nhỉ. Nhưng với database thì đây có thể là hai thứ hoàn toàn khác biệt. PostgreSQL sẽ không tự động đoán ý bạn đâu. Nếu không hiểu rõ cách nó so sánh các giá trị khác kiểu, bạn có thể nhận được kết quả kỳ lạ hoặc thậm chí là lỗi luôn.
Chuyển đổi cũng vậy thôi. Đôi khi bạn cần biến text thành số để đếm xem có bao nhiêu cái gì đó. Hoặc ngược lại — số cần được hiển thị đẹp mắt dưới dạng chuỗi. Hoặc lấy ngày tháng và xuất ra kiểu "01.01.2025" cho quen mắt người dùng.
Ví dụ khác: bạn lưu giá trị chính xác trong NUMERIC, nhưng để tính toán khoa học lại cần dùng FLOAT. Lúc này mà không chuyển đổi rõ ràng thì chịu luôn.
Tin vui là PostgreSQL xử lý chuyện này rất ổn. Nó cung cấp công cụ linh hoạt, dễ hiểu cho các tình huống này. Quan trọng là biết dùng và đừng ngại “soi” kỹ hơn một chút. Giờ mình cùng tìm hiểu nhé.
So sánh kiểu dữ liệu
PostgreSQL khá thông minh — nếu thấy bạn so sánh, ví dụ, INTEGER và NUMERIC, nó sẽ tự động chuyển về cùng kiểu và so sánh luôn. Bình thường thôi, vì cả hai đều là số mà.
Nhưng nếu bạn thử so sánh chuỗi với giá trị boolean (TEXT và BOOLEAN), database sẽ không hiểu bạn muốn gì đâu. Hai kiểu này bản chất khác nhau hoàn toàn, PostgreSQL sẽ trả về lỗi ngay. Tương tự, nếu bạn thử so sánh chuỗi "42" với số 42 mà không nói rõ là muốn chuyển chuỗi thành số.
Thực tế sẽ như này, ví dụ này sẽ báo lỗi:
SELECT '42' = 42; -- Lỗi! Chuỗi và số không so sánh được nếu không chuyển đổi
Còn như này thì chạy ngon lành:
SELECT '42'::INTEGER = 42; -- TRUE
Ở đây mình nói rõ: “Làm ơn, chuyển '42' thành số trước nhé”. Đó là lý do có cú pháp ::Kiểu mà mình đã nhắc tới. PostgreSQL thích khi bạn nói chuyện rõ ràng với nó.
So sánh kiểu số
Các kiểu số (INTEGER, NUMERIC, REAL) thường tương thích với nhau, nên bạn có thể so sánh mà không gặp khó khăn gì:
SELECT 42 = 42.0; -- TRUE
SELECT 42::REAL = 42.0; -- TRUE
SELECT 42.0::NUMERIC = 42; -- TRUE
Nhưng cẩn thận với số thực (REAL). Do giới hạn về độ chính xác, các số này đôi khi sẽ “lạ lắm”. Ví dụ:
SELECT 0.1 + 0.2 = 0.3; -- FALSE
Đây chắc là bí ẩn nổi tiếng nhất trong lập trình rồi nhỉ? So sánh này trả về FALSE vì cách lưu trữ số thực trong bộ nhớ máy tính.
So sánh kiểu text
Khi làm việc với kiểu text, bạn có thể so sánh CHAR, VARCHAR và TEXT, vì PostgreSQL sẽ tự động chuyển về kiểu tương thích:
SELECT 'Hello' = 'Hello'::TEXT; -- TRUE
SELECT 'World'::CHAR(5) = 'World'::VARCHAR; -- TRUE
Lưu ý về độ dài ký tự trong CHAR(n): nếu chuỗi ngắn hơn độ dài chỉ định, PostgreSQL sẽ tự động thêm dấu cách vào cuối.
Chuyển đổi kiểu dữ liệu
PostgreSQL có vài cách để chuyển đổi kiểu dữ liệu. Mình sẽ nói về hai cách chính:
Cách #1: Chuyển đổi rõ ràng (CAST)
Toán tử CAST cho phép bạn chỉ định rõ muốn chuyển kiểu nào sang kiểu nào. Ví dụ:
SELECT CAST('42' AS INTEGER); -- Chuyển chuỗi '42' thành số 42
Cách này đặc biệt tiện nếu bạn muốn code SQL dễ đọc hơn.
Cách #2: Viết tắt (::)
PostgreSQL còn có cú pháp ngắn gọn hơn để chuyển đổi kiểu — dùng ::. Vẫn là thao tác đó, chỉ là viết nhanh hơn:
SELECT '42'::INTEGER; -- Giống hệt CAST('42' AS INTEGER)
Chuyển đổi tự động
Nhiều trường hợp PostgreSQL sẽ tự động chuyển đổi dữ liệu. Ví dụ, dùng số trong trường kiểu chuỗi:
SELECT '42' = 42::TEXT; -- TRUE
Nhưng đừng quá tin vào chuyển đổi tự động, vì nó có thể gây bất ngờ cho dev khác. Đặc biệt với ngày tháng và chuỗi, nên chuyển đổi rõ ràng thì hơn.
Ví dụ chuyển đổi các kiểu dữ liệu khác nhau
Chuyển số thành text
Đôi khi bạn cần chuyển số thành text (ví dụ để tạo thông báo):
SELECT 42::TEXT; -- Chuyển số 42 thành chuỗi '42'
SELECT 3.14::TEXT; -- Chuyển số 3.14 thành chuỗi '3.14'
Chuyển text thành số
Nếu chuỗi chứa số hợp lệ, bạn có thể chuyển nó thành kiểu số:
SELECT '123'::INTEGER; -- Chuyển chuỗi '123' thành số 123
SELECT '3.14'::FLOAT; -- Chuyển chuỗi '3.14' thành số 3.14
Nhưng nếu text không chuyển được thì sao? Ví dụ:
SELECT 'Hello'::INTEGER; -- Lỗi: không thể chuyển 'Hello' thành số
Để tránh lỗi kiểu này, bạn có thể dùng hàm TRY_CAST() (từ PostgreSQL 14 trở lên) hoặc kiểm tra dữ liệu trước.
Chuyển ngày thành text và ngược lại
Khi chuyển đổi ngày tháng, bạn có thể dùng hàm TO_CHAR() và TO_DATE():
SELECT TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD'); -- Chuyển ngày thành chuỗi
SELECT TO_DATE('2023-10-25', 'YYYY-MM-DD'); -- Chuyển chuỗi thành ngày
Chuyển đổi giữa BOOLEAN và text
Kiểu dữ liệu logic BOOLEAN cũng có thể chuyển thành chuỗi:
SELECT TRUE::TEXT; -- 'true'
SELECT FALSE::TEXT; -- 'false'
Hoặc ngược lại:
SELECT 'true'::BOOLEAN; -- TRUE
SELECT 'false'::BOOLEAN; -- FALSE
Lưu ý, các chuỗi như 'yes' hoặc 'no' sẽ không tự động chuyển đổi được đâu nhé.
Thực hành: tất cả bằng ví dụ thực tế
Tạo bảng minh họa việc dùng các kiểu dữ liệu khác nhau:
| 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 |
Giờ thử các thao tác chuyển đổi nhé:
-- Chuyển text thành số
SELECT number_as_text::INTEGER FROM data_types_demo WHERE number_as_text = '42';
-- Chuyển ngày thành text
SELECT TO_CHAR(actual_date, 'DD/MM/YYYY') FROM data_types_demo;
-- Chuyển chuỗi thành ngày
SELECT TO_DATE(date_as_text, 'YYYY-MM-DD') FROM data_types_demo;
Lỗi thường gặp khi chuyển đổi dữ liệu
Lỗi phổ biến gồm có:
- Thử chuyển đổi dữ liệu không đúng định dạng mong đợi (ví dụ, chuỗi
'Hello'sangINTEGER). - Vấn đề làm tròn và độ chính xác khi làm việc với số thực.
- Dùng sai định dạng khi chuyển đổi ngày tháng.
Để tránh lỗi, nên:
- Luôn kiểm tra dữ liệu trước khi chuyển đổi.
- Dùng hàm xử lý lỗi (
TRY_CASThoặcCASE). - Chỉ định định dạng rõ ràng khi chuyển đổi ngày tháng.
-- Kiểm tra dữ liệu trước khi chuyển đổi
SELECT
CASE
WHEN number_as_text ~ '^\d+$' THEN number_as_text::INTEGER
ELSE NULL
END AS safe_integer
FROM data_types_demo;
Dùng cách này để bảo vệ truy vấn của bạn khỏi những tình huống bất ngờ nhé!
Đến đây bạn đã có kỹ năng cơ bản để so sánh và chuyển đổi kiểu dữ liệu trong PostgreSQL rồi. Còn lại chỉ là luyện tập, luyện tập và luyện tập thôi. Hẹn gặp lại ở các bài giảng tiếp theo nhé!
GO TO FULL VERSION