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

Hàm ① — Số học, Nối chuỗi và Hàm ngày tháng

Bài đầu trong ba bài về hàm SQL. Bao gồm các toán tử số học + - * / %, nối chuỗi với || và CONCAT, và các hàm ngày tháng như thời gian hiện tại và trích xuất năm / tháng — tất cả trên tập dữ liệu staff được tải từ CSV.

Dữ liệu dùng trong bài này — bảng staff

Bắt đầu từ bài này, ba bài tiếp theo bao gồm các hàm được tích hợp sẵn trong SQL. Bài đầu tiên tập trung vào ba nhóm: phép toán số học, nối chuỗi, và hàm ngày tháng — tất cả đều là biểu thức bạn thường đặt vào danh sách cột của SELECT.

Tập dữ liệu là bảng staff (10 hàng: id / name / birthday / city / salary), được tự động tải từ CSV. Qua bốn bài thực hành, bạn sẽ làm phép tính tiền với salary, xây dựng nhãn từ namecity, và định dạng ngày từ birthday.

Trước khi bắt đầu các bài thực hành, hãy kiểm tra định nghĩa cộtdữ liệu mẫu của bảng staff.

① Chạy PRAGMA table_info(staff); để xem tên cột, kiểu và khóa chính.

② Chạy SELECT * FROM staff LIMIT 5; để xem trước 5 hàng đầu tiên.

SQL Editor

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

Toán tử số học — +, -, *, /, %

Đối với phép tính trên cột số, bạn có 5 toán tử số học + - * / %. SQL cho phép bạn viết biểu thức trực tiếp trong danh sách cột của SELECT, nên bạn có thể lấy giá trị từ bảng và trả về kết quả đã tính dưới dạng cột riêng. Thêm AS bí_danh đặt tên cho cột kết quả, giúp dễ hiển thị hoặc xử lý ở mã downstream.

Phép chia / hoạt động khác nhau giữa các CSDL: trong phép chia giữa hai số nguyên, một số CSDL (PostgreSQL / SQL Server) trả về kết quả nguyên, trong khi các CSDL khác (MySQL / console của khóa học này = SQLite) tự động trả về số thập phân.

-- 1) Phép tính đơn giản không cần bảng
SELECT 1 + 1;       -- 2
SELECT 10 - 3;      -- 7
SELECT 3 * 4;       -- 12
SELECT 10.0 / 3;    -- 3.333...
SELECT 10 % 3;      -- 1

-- 2) Phép tính dùng cột (lương năm sau khi tăng 10%)
SELECT name, salary, salary * 1.1 AS next_year_salary
FROM staff;

-- 3) Tính lương tháng (năm / 12)
SELECT name, salary / 12 AS monthly_salary FROM staff;
Bảng tra cứu toán tử số học
Toán tửÝ nghĩaVí dụ+Cộngsalary + 100000-Trừsalary - 100000*Nhânsalary * 1.1/Chiasalary / 12%Modulo(số dư)10 % 3 → 1
Các toán tử số học chính được tích hợp sẵn trong SQL. 5 toán tử + - * / % có cùng ý nghĩa như trong hầu hết các ngôn ngữ lập trình.

Hãy tưởng tượng một mô phỏng lương: hiển thị «lương năm của mỗi nhân viên nếu họ được tăng 10%». (Nếu bạn chạy đúng, một giải thích sẽ hiện ra.)

① Từ bảng staff, lấy name, salary, và salary * 1.1 với bí danh next_year_salary — tổng 3 cột.

② Sắp xếp theo next_year_salary giảm dần.

③ Kiểm tra kết quả có 10 hàng và bắt đầu với Frank Tanaka 7,200,000 / 7,920,000.

SQL Editor

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

Nối chuỗi — `||` và `CONCAT()`

Việc nối nhiều chuỗi thành một được gọi là nối chuỗi (concatenation). Có hai cách viết: console của khóa học này (SQLite), PostgreSQL, Oracle và SQL Server dùng toán tử `||` (hai gạch đứng), trong khi MySQL dùng hàm `CONCAT()`. SQLite thực ra hỗ trợ cả hai ||CONCAT(), nên bài này tập trung vào hàm CONCAT() có tính di động cao hơn.

Bằng cách chèn dấu phân cách (': ' hoặc ' / ') giữa các giá trị, bạn có thể gộp namecity thành một cột dễ đọc như «Alice Tanaka / Tokyo». Đây là công cụ chủ lực cho báo cáo và xuất CSV khi bạn muốn «gộp nhiều cột thành một».

-- 1) Toán tử || (SQLite / PostgreSQL / Oracle)
SELECT name || ' (' || city || ')' AS label FROM staff;

-- 2) Hàm CONCAT (MySQL / SQLite 3.40+ / PostgreSQL)
SELECT CONCAT(name, ' (', city, ')') AS label FROM staff;

-- Cả hai trả về cùng kết quả
-- → Alice Tanaka (Tokyo) / Bob Suzuki (Osaka) / ...

`||` vs. `CONCAT()` — chọn cái nào

Vì tính di động, `CONCAT()` là lựa chọn an toàn hơn. Nó chạy trên SQLite, MySQL, PostgreSQL, SQL Server (2012+) và Oracle. || là chuẩn SQL, nhưng trong MySQL nó mặc định là OR logic, nên nếu môi trường production có thể là MySQL, chọn CONCAT() nghĩa là bạn không cần viết lại gì.

Xử lý NULL cũng khác nhau: NULL || 'A' trả về NULL với toán tử ||. CONCAT(NULL, 'A') trả về chuỗi rỗng trong MySQL nhưng NULL trong PostgreSQL — hành vi khác nhau. Khi NULL có thể lẻn vào dữ liệu đầu vào, bao chúng bằng COALESCE(cột, '') để chuyển NULL thành chuỗi rỗng trước khi nối (COALESCE được đề cập trong bài thứ ba của loạt bài này).

Hãy tưởng tượng xây dựng nhãn cho thẻ nhân viên: «tên theo sau bởi khoảng trắng và thành phố trong dấu ngoặc».

① Từ bảng staff, lấy hai cột gốc namecity cùng với `CONCAT(name, ' (', city, ')')` với bí danh `label`.

② Kiểm tra kết quả có 10 hàng và cột label chứa các chuỗi như «Alice Tanaka (Tokyo)» / «Bob Suzuki (Osaka)».

SQL Editor

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

Hàm ngày tháng — thời gian hiện tại và định dạng

Đối với những việc như «đóng dấu thời gian hiện tại lên bản ghi mới» hoặc «trích xuất chỉ năm từ sinh nhật», bạn dùng hàm ngày tháng. Hàm ngày tháng là một trong những nhóm mà tên hàm và cú pháp khác nhau nhiều nhất giữa các CSDL — console của khóa học này (SQLite) và MySQL gọi chúng khá khác nhau.

Khóa học này dùng datetime('now') / date('now') / strftime('format', giá_trị) của SQLite cho các bài thực hành, với NOW() / CURDATE() / DATE_FORMAT(giá_trị, 'format') của MySQL được hiển thị song song trong bảng so sánh bên dưới. Các chuỗi định dạng ('%Y' cho năm, '%m' cho tháng, '%d' cho ngày, v.v.) giống nhau trong cả hai CSDL, nên ít nhất các định danh định dạng chuyển trực tiếp.

-- Cách viết trong console của khóa học này (SQLite)

-- 1) Thời gian hiện tại / ngày hiện tại
SELECT datetime('now') AS current_dt, date('now') AS current_d;

-- 2) Định danh định dạng (chỉ năm / năm-tháng)
SELECT strftime('%Y', '1990-04-15') AS year_only;       -- '1990'
SELECT strftime('%Y-%m', '1990-04-15') AS year_month;   -- '1990-04'

-- 3) Định dạng áp dụng cho cột
SELECT name, strftime('%Y', birthday) AS birth_year FROM staff;

-- Tham khảo: tương tự trong MySQL
--   SELECT NOW(), CURDATE();
--   SELECT DATE_FORMAT(birthday, '%Y') FROM staff;
Mục đíchConsole khóa học này (SQLite)MySQL
Thời gian hiện tạidatetime('now')NOW()
Ngày hiện tạidate('now')CURDATE()
Trích xuất nămstrftime('%Y', d)DATE_FORMAT(d, '%Y')
Định dạng tùy chỉnhstrftime('%Y-%m-%d', d)DATE_FORMAT(d, '%Y-%m-%d')

Hãy lấy thời gian hiện tạingày hiện tại từ console của khóa học này. Chạy là đủ — không có kiểm tra chính xác.

① Lấy datetime('now') với bí danh current_dtdate('now') với bí danh current_d.

② Kiểm tra kết quả là 1 hàng × 2 cột, với current_dt hiển thị thời gian hiện tại định dạng «YYYY-MM-DD HH:MM:SS» và current_d hiển thị ngày hiện tại định dạng «YYYY-MM-DD».

SQL Editor

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

Hãy tưởng tượng danh sách nhân viên cần một cột «năm sinh» riêng.

① Từ bảng staff, lấy name, birthday, và `strftime('%Y', birthday)` với bí danh `birth_year` — tổng 3 cột.

② Kiểm tra kết quả có 10 hàng. Đối với Alice Tanaka, bạn sẽ thấy birthday=1990-04-15birth_year='1990' — chỉ năm nằm trong cột mới.

SQL Editor

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

Hãy tưởng tượng một yêu cầu: «hiển thị các nhân viên trẻ (sinh trong những năm 1990) theo thứ tự sinh».

① Từ bảng staff, lấy name, birthday, và strftime('%Y', birthday) AS birth_year.

② Lọc các hàng có birth_year từ '1990' đến '1999' (dùng BETWEEN).

③ Sắp xếp theo birthday tăng dần (sớm nhất trước) và chỉ giữ 3 hàng đầu.

④ Kiểm tra kết quả là 3 hàng: Alice 1990-04-15 / Grace 1991-05-25 / Carol 1992-11-03.

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 những đáp án sau, đâu là kết quả đúng của SELECT 10 % 3;?

Câu 2Trong console của khóa học này, đâu là cách đúng để gộp namecity thành một cột như Alice Tanaka (Tokyo)?

Câu 3Trong console của khóa học này (SQLite), đâu là cách đúng để trích xuất chỉ năm 4 chữ số từ cột birthday?