Học bằng cách đọc theo thứ tự

Chuỗi, số, kiểu boolean và chuyển đổi kiểu ngầm định

Dùng bảng typed_demo để thấy kiểu khai báo khác lớp lưu trữ ra sao, xem '10' và 123 chuyển qua lại với typeof(), tìm hiểu boolean được biểu diễn bằng 0 / 1, và so sánh tất cả với các kiểu nghiêm ngặt CHAR / VARCHAR / INT / DECIMAL của MySQL bằng cách chạy truy vấn thật.

Dữ liệu sẽ dùng — bảng typed_demo

Khi bạn tạo một cột, bạn khai báo một kiểu như INTEGER / TEXT / REAL, và kiểu đó quyết định cách cột xử lý các giá trị mà nó chứa.

Trong bài này bạn sẽ đi qua cách chuỗi, số và boolean được lưu trữ và so sánh trong SQL, và cách console của khóa học này xử lý kiểu (được gọi là type affinity trong tài liệu SQLite) khác với các kiểu nghiêm ngặt trong MySQL ra sao.

Trước khi vào bài tập, hãy xem nhanh định nghĩa cộtdữ liệu mẫu của bảng typed_demo. (Chạy đúng và phần giải thích sẽ hiện ra.)

① Dùng PRAGMA table_info(typed_demo); để kiểm tra tên cột, kiểu khai báo và khóa chính.

② Dùng SELECT * FROM typed_demo; để xem trước toàn bộ dòng.

SQL Editor

Chạy truy vấn để xem kết quả

Kiểu khai báo so với lớp lưu trữ — mỗi giá trị mang kiểu riêng

Kiểu mà một giá trị thực sự có lúc chạy được gọi là lớp lưu trữ (storage class), và có năm loại: NULL / INTEGER (số nguyên) / REAL (số thập phân) / TEXT (chuỗi) / BLOB (nhị phân).

Bạn có thể kiểm tra lớp lưu trữ hiện tại của một giá trị với hàm typeof(giá_trị).

Nếu bạn đưa một chuỗi trông giống số vào cột khai báo TEXT, chính sách của cột là "xem đây là text", nên nó vẫn là chuỗi.

Nhưng nếu bạn đưa một chuỗi trông giống số như '123' vào cột khai báo INTEGER, chính sách của cột sẽ áp dụng và chuyển nó thành số nguyên 123 trước khi lưu.

Kiểu khai báo so với lớp lưu trữ
Giá trị chèn vàoKiểu cột khai báoKiểu được lưu'123'Cột INTEGERinteger 123(typeof=integer)'10'Cột TEXTstring '10'(typeof=text)
Kiểu bạn khai báo trên một cột là chính sách cho "giá trị này sẽ được xử lý thế nào". '123' vào cột INTEGER trở thành số nguyên, trong khi '10' vào cột TEXT vẫn là chuỗi. Kiểu thực tế của mỗi giá trị luôn có thể kiểm tra bằng typeof().
-- Ví dụ độc lập minh họa "kiểu khai báo của cột quyết định kiểu được lưu"
-- Chuỗi trông giống số trong cột INTEGER sẽ được chuyển thành số nguyên
CREATE TABLE IF NOT EXISTS aff_probe(num INTEGER, txt TEXT);
INSERT OR IGNORE INTO aff_probe VALUES ('123','123'), ('hello','hello');

-- Dùng typeof để kiểm tra lớp lưu trữ thực tế
SELECT num, typeof(num) AS num_class,
       txt, typeof(txt) AS txt_class
FROM aff_probe;
-- Cột num: '123' thành integer, 'hello' không chuyển được nên vẫn là text
-- Cột txt: cả hai đều là text

Hãy tưởng tượng bạn muốn kiểm tra "từng giá trị trong typed_demo thực tế được lưu dưới kiểu nào (integer / real / string)".

① Lấy các cột a, b, c, và flag từ typed_demo.

② Thêm typeof() cho mỗi cột, với bí danh a_class / b_class / c_class / flag_class.

③ Đừng lọc dòng — cả hai dòng đều xuất hiện trong kết quả.

SQL Editor

Chạy truy vấn để xem kết quả

Chuỗi và số chuyển qua lại — '123' và 123

Khi cần một số, chuỗi sẽ được chuyển thành số tự động; khi cần một chuỗi, số sẽ được chuyển thành chuỗi.

Ví dụ, '123' + 0 chuyển chuỗi '123' thành số 123 và trả về 123, nên các chuỗi trông giống số có thể đưa thẳng vào phép tính.

Ngược lại, 123 || '' (|| là phép nối chuỗi) biến số thành chuỗi.

Các toán tử so sánh hoạt động theo cách tương tự: nếu một bên là cột INTEGER, bên kia được căn chỉnh thành số; nếu một bên là cột TEXT, bên kia được căn chỉnh thành chuỗi.

Nhưng với hai literal thô như '1' = 1 không có cột nào để đặt chính sách, nên các giá trị giữ nguyên kiểu khác nhau và kết quả là 0 (không khớp).

Chuỗi và số chuyển đổi theo ngữ cảnh
Biểu thứcChuyển đổiKết quả'123' + 0'123' thànhsố 123123'abc' + 0không chuyển được,xem như 00
Khi cần phép tính, chuỗi trông giống số thành số; khi cần nối chuỗi, số thành chuỗi. Chuỗi như 'abc' không thể chuyển thành số được xem như 0 trong phép tính.
-- Quan sát chuyển đổi chuỗi <-> số (ví dụ chỉ đọc)
SELECT '123' + 0     AS str_to_num,   -- chuỗi thành số 123
       'abc' + 0     AS not_a_num,    -- không chuyển được, thành 0
       123 || ''     AS num_to_str,   -- số thành chuỗi '123'
       typeof('123' + 0) AS class_after_add,
       '1' = 1       AS literal_cmp,  -- literal thô: 0 (không khớp)
       7 / 2         AS int_div,      -- integer / integer = integer 3
       7.0 / 2       AS real_div;     -- có số thập phân thì cho 3.5

Hãy tưởng tượng bạn muốn "xử lý các chuỗi trông giống số trong cột b (TEXT) của typed_demo như số để tính toán và so sánh".

① Lấy cột b từ typed_demo.

② Thêm b + 0 với bí danh b_plus0. Các dòng trông giống số thành số, còn các dòng không phải số thành 0.

③ Sau đó thêm phép kiểm tra xem b dưới dạng số có lớn hơn 5 không, với bí danh gt5 (vì bạn đang so sánh giá trị cột b với một literal số, phép so sánh diễn ra giữa các số).

SQL Editor

Chạy truy vấn để xem kết quả

Boolean — TRUE / FALSE được lưu dưới dạng 1 / 0

SQL không có kiểu boolean độc lập — các giá trị chân lý được biểu diễn bằng số nguyên 1 (true) và 0 (false).

Các biểu thức so sánh như 1 = 1 hoặc 3 > 2 trả về 1 cho true và 0 cho false.

Ở bất cứ chỗ nào bạn có thể viết điều kiện, như CASE WHEN cột THEN ..., bất kỳ giá trị nào khác 0 (thường là 1) được xem là true, còn 0 được xem là false.

NULL là trạng thái thứ ba không phải true cũng không phải false ("không xác định"), và trong điều kiện WHERE hoặc CASE nó hành xử như false theo nghĩa dòng đó "không được chọn".

Boolean là integer 1 / 0
Biểu thức / giá trịDiễn giải boolean1 / TRUE / 3>2true0 / FALSE / 1>2falseNULLkhông xác định — không chọn
Các biểu thức so sánh trả về 1 cho true và 0 cho false. Cột flag chứa 1 / 0 có thể dùng trực tiếp làm điều kiện, và NULL được xem như trạng thái thứ ba không phải true cũng không phải false.
-- Biểu thức so sánh trả về 1 / 0 (ví dụ chỉ đọc)
SELECT (1 = 1)  AS is_true,    -- 1
       (1 = 2)  AS is_false,   -- 0
       (3 > 2)  AS gt,         -- 1
       TRUE     AS true_kw,    -- giống 1
       FALSE    AS false_kw;   -- giống 0

-- Dùng cột flag trực tiếp làm điều kiện
SELECT a, flag,
  CASE WHEN flag THEN 'enabled' ELSE 'disabled' END AS state
FROM typed_demo;

Hãy tưởng tượng bạn muốn "biến cột flag (integer 1 / 0) trong typed_demo thành nhãn người đọc được".

① Lấy aflag từ typed_demo.

② Dùng flag trực tiếp làm điều kiện trong CASE WHEN ... và thêm cột thứ ba với bí danh state trả về 'enabled' cho các dòng true (1) và 'disabled' cho các dòng false (0).

③ Để cũng thấy biểu thức so sánh trả về gì cho true / false, hãy thêm cột thứ tư với kết quả của flag = 1 với bí danh is_on.

SQL Editor

Chạy truy vấn để xem kết quả

So sánh với các kiểu nghiêm ngặt của MySQL

Những gì bạn vừa thấy là chuyển đổi kiểu ngầm định — các giá trị được định hình lại linh hoạt dựa theo ngữ cảnh.

Ngược lại, MySQL và Oracle có kiểu nghiêm ngặt: khi bạn khai báo CHAR(10) / VARCHAR(255) / TEXT cho chuỗi hoặc INT / DECIMAL(10,2) cho số, chỉ giá trị của kiểu đó mới được nạp vào, và độ dài và độ chính xác được áp đặt đúng như khai báo.

Một số thường không lọt vào cột chuỗi qua chuyển đổi ngầm, và các giá trị vượt quá độ dài khai báo sẽ báo lỗi hoặc bị cắt bớt.

Đoạn code bên dưới là cách MySQL khai báo kiểu.

Console của khóa học này không kiểm tra độ dài theo thiết kế, nên khi bạn học các ràng buộc độ dài như VARCHAR(10), hãy nhớ "MySQL viết như vậy" — cú pháp đó sẽ chuyển sang được khi bạn chuyển sang các cơ sở dữ liệu khác.

Chuyển đổi kiểu ngầm định so với kiểu nghiêm ngặt của MySQL
Console khóa học này(chuyển đổi ngầm định)MySQL(kiểu nghiêm ngặt)'123' vào cột INTEGER ->lưu thành integer 123Cột INT = chỉ số /VARCHAR(10) = tối đa 10 ký tựKhông ép buộcđộ dài / độ chính xácVượt độ dài:lỗi / cắt bớt
Console của khóa học này dùng chuyển đổi kiểu ngầm định — '123' chèn vào cột INTEGER thành integer và câu lệnh chạy được. MySQL dùng kiểu nghiêm ngặt — kiểu khai báo và độ dài được áp đặt, và các giá trị không khớp sẽ báo lỗi hoặc bị cắt bớt.
-- Khai báo kiểu nghiêm ngặt trong MySQL (chỉ đọc — đừng chạy trên console này)
CREATE TABLE product (
  id        INT            PRIMARY KEY,   -- chỉ số nguyên
  code      CHAR(8),                      -- độ dài cố định, 8 ký tự
  name      VARCHAR(100)   NOT NULL,      -- tối đa 100 ký tự
  note      TEXT,                         -- chuỗi dài
  price     DECIMAL(10,2)  NOT NULL,      -- 8 chữ số + 2 chữ số thập phân
  in_stock  TINYINT(1)     DEFAULT 0      -- cờ 0/1 cho boolean
);

-- Trong MySQL, đưa 101 ký tự vào VARCHAR(100) sẽ
-- báo lỗi hoặc bị cắt bớt tùy thiết lập.
-- Đưa 'abc' vào cột INT sẽ báo lỗi.
-- Console của khóa học này chạy được tất cả nhờ chuyển đổi kiểu ngầm định.

Tips — CHAR so với VARCHAR và khi nào dùng từng cái

`CHAR(n)`độ dài cố định: nếu giá trị ngắn hơn n ký tự, nó được đệm khoảng trắng phía sau cho đủ n ký tự.

`VARCHAR(n)`độ dài biến đổi: nó giữ giá trị ở độ dài thực tế (n là giới hạn trên).

Chọn `CHAR` khi: giá trị luôn có độ dài cố định, như mã quốc gia ('JP' / 'US'), mã giới tính, hoặc một phần độ dài cố định của một hash. Bố cục cố định có thể nhanh hơn một chút cho phép so sánh và tính vị trí bản ghi.

Chọn `VARCHAR` khi: độ dài thay đổi — tên, địa chỉ email, tiêu đề, mô tả, v.v. Nó chỉ chiếm không gian thực sự cần, nên dung lượng lưu trữ nhỏ hơn.

Khi chưa chắc, `VARCHAR` là mặc định an toàn hơn. Dùng CHAR cho dữ liệu có độ dài thay đổi có thể gây ra các trường hợp so sánh không khớp tinh tế vì phần đệm khoảng trắng phía sau (ví dụ 'JP' so với 'JP ' được xử lý không đồng nhất).

Hãy tưởng tượng bạn muốn "tính tổng và trung bình các giá trị trong cột b (TEXT) của typed_demo như số, và đếm xem có bao nhiêu dòng là true trong cột flag". Điều này cho thấy chuyển đổi kiểu ngầm định cho phép bạn tổng hợp các cột text theo cách số học.

① Lấy tổng của cột b trong typed_demo với bí danh sum_b, và trung bình với bí danh avg_b. Chỉ các dòng trông giống số được cộng vào dưới dạng số.

② Trong cùng truy vấn, lấy tổng của cột flag với bí danh enabled_count (vì flag là 1 / 0, tổng bằng số dòng true).

③ Đừng nhóm theo gì cả — trả về một dòng tóm tắt duy nhất cho cả bảng.

SQL Editor

Chạy truy vấn để xem kết quả
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Trong console của khóa học này, bạn INSERT chuỗi '123' vào cột khai báo INTEGER. Phát biểu nào đúng?

Câu 2Phát biểu nào mô tả đúng cách boolean được biểu diễn trong SQL?

Câu 3Phát biểu nào mô tả đúng sự khác biệt giữa console của khóa học này (chuyển đổi kiểu ngầm định) và kiểu nghiêm ngặt của MySQL?