Hướng dẫn chi tiết về ngôn ngữ truy vấn dữ liệu từ cơ bản đến nâng cao
Trong kỷ nguyên số, dữ liệu được ví như "dầu mỏ" mới, và SQL (Structured Query Language - Ngôn ngữ truy vấn có cấu trúc) chính là một trong những công cụ để khai thác "mỏ dầu" đó. Đây là kỹ năng không thể thiếu đối với bất kỳ ai làm việc với dữ liệu, từ nhà phân tích, kỹ sư phần mềm cho đến các nhà quản lý sản phẩm. Việc hiểu và sử dụng thành thạo SQL mở ra cánh cửa để khai thác thông tin quý giá từ các cơ sở dữ liệu quan hệ, không chỉ để truy vấn mà còn để tạo, sửa đổi và quản lý toàn bộ cấu trúc dữ liệu.
Bài viết này sẽ là một hướng dẫn chi tiết, đi từ những khái niệm cơ bản nhất đến các kỹ thuật nâng cao, giúp bạn hiểu rõ và tự tin sử dụng SQL trong công việc hàng ngày.
Các loại lệnh SQL chính
Trước khi đi sâu vào chi tiết, điều quan trọng là phải hiểu rằng SQL không chỉ là một lệnh duy nhất mà là một tập hợp các nhóm lệnh, mỗi nhóm phục vụ một mục đích khác nhau trong vòng đời của dữ liệu:
- Ngôn ngữ định nghĩa dữ liệu (DDL - Data Definition Language): Dùng để tạo và quản lý cấu trúc của cơ sở dữ liệu. Các lệnh chính bao gồm CREATE, ALTER, DROP.
- Ngôn ngữ thao tác dữ liệu (DML - Data Manipulation Language): Dùng để quản lý dữ liệu bên trong các bảng, bao gồm việc thêm, sửa, xóa và truy vấn. Các lệnh phổ biến là INSERT, UPDATE, DELETE, và SELECT.
- Ngôn ngữ điều khiển dữ liệu (DCL - Data Control Language): Dùng để quản lý quyền truy cập vào dữ liệu.
- Ngôn ngữ điều khiển giao dịch (TCL - Transaction Control Language): Dùng để quản lý các giao dịch trong cơ sở dữ liệu.
Trong bài viết này, chúng ta sẽ tập trung chủ yếu vào DDL và DML, những nhóm lệnh phổ biến và quan trọng nhất.
Một lưu ý quan trọng về các phiên bản SQL
Mặc dù có một tiêu chuẩn SQL được công nhận bởi ANSI và ISO, nhưng thực tế là các RDBMS (hệ quản trị cơ sở dữ liệu quan hệ) khác nhau có thể sử dụng các phiên bản hơi khác nhau của ngôn ngữ. Điều này có nghĩa là một câu lệnh SQL hoạt động hoàn hảo trên MySQL có thể cần một chút điều chỉnh nhỏ để chạy trên Oracle hoặc SQL Server. Các khác biệt phổ biến bao gồm:
- Kiểu dữ liệu: Cách xử lý kiểu dữ liệu ngày giờ (DATE, TIME, DATETIME).
- Hàm tích hợp: Tên và cú pháp của các hàm có thể khác nhau.
- Cú pháp nâng cao: Cách viết các lệnh như OUTER JOIN, các toán tử tập hợp (INTERSECT, EXCEPT/MINUS), hay cách xử lý giá trị NULL.
Tuy nhiên, đừng quá lo lắng. Các lệnh cốt lõi như SELECT, INSERT, UPDATE, DELETE, và INNER JOIN gần như giống hệt nhau trên mọi nền tảng. Sự khác biệt chỉ thực sự đáng chú ý khi bạn làm việc với các tính năng nâng cao.
Nền tảng của cơ sở dữ liệu: Ngôn ngữ định nghĩa dữ liệu (DDL)
Giống như xây một ngôi nhà, trước khi có thể "ở" (lưu trữ dữ liệu), chúng ta cần xây dựng "khung" (cấu trúc). DDL chính là bộ công cụ của người kiến trúc sư cơ sở dữ liệu.
CREATE TABLE: Xây dựng bảng dữ liệu
Lệnh CREATE TABLE được dùng để tạo một bảng mới trong cơ sở dữ liệu. Khi tạo bảng, bạn cần định nghĩa tên các cột, kiểu dữ liệu cho mỗi cột (ví dụ: VARCHAR cho chuỗi, INT cho số nguyên, DATE cho ngày tháng), và các ràng buộc như khóa chính (PRIMARY KEY) hay khóa ngoại (FOREIGN KEY).
Ví dụ: Tạo bảng VENDOR, CATEGORY và PRODUCT.
\-- Tạo bảng VENDOR
CREATE TABLE VENDOR (
VendorID CHAR(2) NOT NULL,
VendorName VARCHAR(25) NOT NULL,
PRIMARY KEY (VendorID)
);
\-- Tạo bảng CATEGORY
CREATE TABLE CATEGORY (
CategoryID CHAR(2) NOT NULL,
CategoryName VARCHAR(25) NOT NULL,
PRIMARY KEY (CategoryID)
);
\-- Tạo bảng PRODUCT với khóa ngoại tham chiếu đến VENDOR và CATEGORY
CREATE TABLE PRODUCT (
ProductID CHAR(3) NOT NULL,
ProductName VARCHAR(25) NOT NULL,
ProductPrice NUMERIC(7, 2) NOT NULL,
VendorID CHAR(2) NOT NULL,
CategoryID CHAR(2) NOT NULL,
PRIMARY KEY (ProductID),
FOREIGN KEY (VendorID) REFERENCES VENDOR(VendorID),
FOREIGN KEY (CategoryID) REFERENCES CATEGORY(CategoryID)
);
Lưu ý: Bảng có chứa khóa ngoại (PRODUCT) phải được tạo sau các bảng mà nó tham chiếu đến (VENDOR, CATEGORY).
ALTER TABLE: Sửa đổi cấu trúc bảng
Khi nhu cầu thay đổi, bạn có thể cần thêm, xóa hoặc sửa đổi các cột trong một bảng đã tồn tại. ALTER TABLE là lệnh dành cho việc này.
Ví dụ: Thêm một cột số điện thoại vào bảng VENDOR.
ALTER TABLE VENDOR ADD (
VendorPhoneNumber CHAR(12)
);
DROP TABLE: Xóa bảng
Lệnh DROP TABLE dùng để xóa hoàn toàn một bảng và tất cả dữ liệu bên trong nó.
Ví dụ: Xóa bảng SOLDVIA.
DROP TABLE SOLDVIA;
Cảnh báo: Cần cẩn thận với thứ tự xóa các bảng. Bạn không thể xóa một bảng đang được tham chiếu bởi khóa ngoại từ một bảng khác.
Thao tác với dữ liệu: Ngôn ngữ thao tác dữ liệu (DML)
Sau khi đã có cấu trúc, bước tiếp theo là đưa dữ liệu vào, cập nhật, xóa và quan trọng nhất là khai thác chúng.
INSERT INTO: Thêm dữ liệu mới
Lệnh INSERT INTO được sử dụng để thêm các hàng (bản ghi) mới vào một bảng.
Ví dụ: Thêm dữ liệu cho bảng VENDOR và PRODUCT.
\-- Thêm nhà cung cấp
INSERT INTO VENDOR VALUES ('PG', 'Pacifica Gear');
INSERT INTO VENDOR VALUES ('MK', 'Mountain King');
\-- Thêm sản phẩm
INSERT INTO PRODUCT VALUES ('1X1', 'TrekStar', 250, 'PG', 'FW');
INSERT INTO PRODUCT VALUES ('2X2', 'Pioneer', 300, 'MK', 'FW');
UPDATE: Cập nhật dữ liệu
UPDATE cho phép bạn chỉnh sửa dữ liệu của các bản ghi đã có. Lệnh này thường đi kèm với mệnh đề WHERE để chỉ định bản ghi nào cần được cập nhật.
Ví dụ: Giả sử bạn nhập sai giá của một sản phẩm. Lệnh sau sẽ sửa giá của sản phẩm có ProductID là '7x7' thành 10.
UPDATE PRODUCT
SET ProductPrice = 10
WHERE ProductID = '7x7';
Nếu không có mệnh đề WHERE, tất cả các hàng trong bảng sẽ bị cập nhật!
DELETE: Xóa dữ liệu
DELETE dùng để xóa các bản ghi khỏi bảng. Tương tự UPDATE, nó rất cần mệnh đề WHERE để xác định đúng bản ghi cần xóa.
Ví dụ: Xóa sản phẩm có ProductID là '7x7'.
DELETE FROM PRODUCT
WHERE ProductID = '7x7';
Trái tim của SQL: Truy vấn dữ liệu với SELECT
Đây là phần thú vị nhất của SQL, nơi bạn đặt câu hỏi và dữ liệu sẽ trả lời. SELECT là lệnh được sử dụng thường xuyên nhất, dùng để lấy dữ liệu từ cơ sở dữ liệu. Kết quả của một lệnh SELECT là một bảng tạm.
Cấu trúc cơ bản
SELECT <tên_cột_1, tên_cột_2, ... hoặc *>
FROM <tên_bảng>
Dấu * đại diện cho việc chọn tất cả các cột.
Ví dụ: Lấy tất cả thông tin từ bảng PRODUCT.
SELECT * FROM PRODUCT;
Ví dụ: Chỉ lấy tên và giá của sản phẩm.
SELECT ProductName, ProductPrice FROM PRODUCT;
WHERE: Lọc dữ liệu
Mệnh đề WHERE dùng để lọc các bản ghi, chỉ trả về những bản ghi thỏa mãn một điều kiện nhất định.
Ví dụ: Lấy các sản phẩm có giá lớn hơn $100.
SELECT ProductID, ProductName, ProductPrice
FROM PRODUCT
WHERE ProductPrice > 100;
Bạn có thể kết hợp nhiều điều kiện bằng AND và OR.
Ví dụ: Lấy các sản phẩm thuộc danh mục 'FW' và có giá nhỏ hơn hoặc bằng $110.
SELECT ProductID, ProductName, VendorID, ProductPrice
FROM PRODUCT
WHERE ProductPrice <= 110 AND CategoryID = 'FW';
ORDER BY: Sắp xếp kết quả
ORDER BY dùng để sắp xếp kết quả trả về theo một hoặc nhiều cột. Mặc định là sắp xếp tăng dần (ASC). Để sắp xếp giảm dần, dùng DESC.
Ví dụ: Lấy sản phẩm thuộc danh mục 'FW' và sắp xếp theo giá giảm dần.
SELECT ProductID, ProductName, CategoryID, ProductPrice
FROM PRODUCT
WHERE CategoryID = 'FW'
ORDER BY ProductPrice DESC;
DISTINCT: Loại bỏ trùng lặp
DISTINCT được sử dụng để chỉ hiển thị các giá trị duy nhất trong một cột.
Ví dụ: Xem danh sách các VendorID khác nhau có trong bảng PRODUCT.
SELECT DISTINCT VendorID FROM PRODUCT;
LIKE: Tìm kiếm theo mẫu
LIKE được dùng trong mệnh đề WHERE để tìm kiếm một chuỗi ký tự theo một mẫu nhất định.
- %: Đại diện cho không, một hoặc nhiều ký tự.
- _: Đại diện cho chính xác một ký tự.
Ví dụ: Tìm tất cả sản phẩm có tên chứa từ 'Boot'.
SELECT *
FROM PRODUCT
WHERE ProductName LIKE '%Boot%';
Sức mạnh của tổng hợp: Các hàm và nhóm dữ liệu
SQL không chỉ lấy dữ liệu thô, nó còn có thể tóm tắt và phân tích dữ liệu ngay trong câu truy vấn. SQL cung cấp các hàm để thực hiện tính toán trên một tập hợp các giá trị.
Các hàm tổng hợp (Aggregate functions)
- COUNT(): Đếm số lượng hàng.
- SUM(): Tính tổng giá trị.
- AVG(): Tính giá trị trung bình.
- MIN(): Tìm giá trị nhỏ nhất.
- MAX(): Tìm giá trị lớn nhất.
Ví dụ: Đếm số lượng sản phẩm và tính giá trung bình, thấp nhất, cao nhất của các sản phẩm thuộc danh mục 'CP'.
SELECT COUNT(*), AVG(ProductPrice), MIN(ProductPrice), MAX(ProductPrice)
FROM PRODUCT
WHERE CategoryID = 'CP';
GROUP BY: Nhóm dữ liệu
Mệnh đề GROUP BY thường được sử dụng cùng với các hàm tổng hợp để nhóm các hàng có cùng giá trị lại thành các nhóm tóm tắt.
Ví dụ: Đối với mỗi nhà cung cấp, hãy đếm số lượng sản phẩm và tính giá trung bình của các sản phẩm họ cung cấp.
SELECT VendorID, COUNT(*), AVG(ProductPrice)
FROM PRODUCT
GROUP BY VendorID;
HAVING: Lọc các nhóm
HAVING tương tự như WHERE, nhưng WHERE lọc các hàng riêng lẻ trước khi tổng hợp, còn HAVING lọc các nhóm sau khi đã được tạo bởi GROUP BY.
Ví dụ: Tìm các nhà cung cấp cung cấp nhiều hơn 1 sản phẩm.
SELECT VendorID, COUNT(*)
FROM PRODUCT
GROUP BY VendorID
HAVING COUNT(*) > 1;
Kết hợp dữ liệu từ nhiều bảng: JOIN
Sức mạnh thực sự của cơ sở dữ liệu quan hệ nằm ở khả năng kết nối dữ liệu từ nhiều bảng khác nhau. Nếu dữ liệu của bạn được chia thành các bảng PRODUCT và VENDOR, làm thế nào để lấy tên sản phẩm cùng với tên nhà cung cấp trong cùng một kết quả? JOIN chính là câu trả lời.
INNER JOIN: Tìm phần giao
INNER JOIN (thường có thể viết tắt là JOIN) là loại kết nối phổ biến nhất. Nó hoạt động như việc tìm phần giao của hai tập hợp. Kết quả trả về là những hàng mà giá trị trong cột kết nối (join key) tồn tại ở cả hai bảng.
Ví dụ: Lấy thông tin sản phẩm kèm theo tên của nhà cung cấp (tên nhà cung cấp nằm ở bảng VENDOR).
SELECT p.ProductID, p.ProductName, v.VendorName, p.ProductPrice
FROM PRODUCT p, VENDOR v
WHERE p.VendorID = v.VendorID;
Trong ví dụ trên, p và v là các bí danh (alias) cho tên bảng, giúp câu lệnh ngắn gọn hơn. Điều kiện p.VendorID = v.VendorID chính là cầu nối giữa hai bảng.
Câu lệnh này yêu cầu hệ thống: "Hãy lấy cho tôi các cột từ bảng PRODUCT và VENDOR, nhưng chỉ giữ lại những hàng nào có VendorID ở bảng PRODUCT khớp với VendorID ở bảng VENDOR."
OUTER JOIN: Giữ lại dữ liệu không khớp
Đôi khi bạn muốn lấy tất cả các bản ghi từ một bảng, kể cả khi chúng không có bản ghi khớp ở bảng kia.
- LEFT JOIN (hoặc LEFT OUTER JOIN): Trả về tất cả các bản ghi từ bảng bên trái và các bản ghi khớp từ bảng bên phải. Nếu không có bản ghi khớp ở bảng phải, các cột của bảng phải sẽ có giá trị NULL.
- RIGHT JOIN (hoặc RIGHT OUTER JOIN): Ngược lại với LEFT JOIN. Nó sẽ trả về tất cả các bản ghi từ bảng bên phải.
- FULL OUTER JOIN: Trả về tất cả bản ghi khi có sự trùng khớp ở một trong hai bảng. Nó là sự kết hợp của LEFT và RIGHT JOIN.
Ví dụ: Lấy danh sách tất cả căn hộ và tên công ty thuê chúng. Kể cả những căn hộ chưa được thuê (LEFT JOIN).
SELECT a.BuildingID, a.AptNo, c.CCName
FROM APARTMENT a LEFT OUTER JOIN CORPCLIENT c
ON a.CCID = c.CCID;
Kết quả sẽ hiển thị tất cả các căn hộ. Những căn hộ nào chưa có người thuê (CCID là NULL hoặc không khớp) sẽ có cột CCName là NULL.
Các khái niệm nâng cao và hữu ích khác
Khi đã thành thạo những kiến thức cơ bản, bạn có thể nâng tầm kỹ năng SQL của mình với những kỹ thuật mạnh mẽ sau đây.
Truy vấn lồng nhau (Nested queries)
Một truy vấn con (subquery) là một câu lệnh SELECT được lồng bên trong một câu lệnh khác (SELECT, INSERT, UPDATE, hoặc DELETE) hoặc bên trong một mệnh đề (WHERE, HAVING, FROM).
Ví dụ: Tìm các sản phẩm có giá thấp hơn giá trung bình của tất cả sản phẩm.
SELECT ProductID, ProductName, ProductPrice
FROM PRODUCT
WHERE ProductPrice < (SELECT AVG(ProductPrice) FROM PRODUCT);
Truy vấn con (SELECT AVG(ProductPrice) FROM PRODUCT) sẽ được thực thi trước để tìm ra giá trung bình, sau đó giá trị này được dùng trong mệnh đề WHERE của truy vấn chính.
SELF JOIN: Bảng tự kết nối với chính nó
Đây là một kỹ thuật đặc biệt khi một bảng có mối liên kết với chính nó. Ví dụ, một bảng EMPLOYEE có cột ManagerID tham chiếu ngược lại đến EmployeeID trong cùng bảng đó. Để lấy tên nhân viên và tên người quản lý của họ, bạn cần JOIN bảng EMPLOYEE với chính nó.
Ví dụ: Lấy tên khách hàng và tên người đã giới thiệu họ (cả hai đều là khách hàng).
SELECT
c.CCName AS Client,
r.CCName AS Recommender
FROM CORPCLIENT c, CORPCLIENT r
WHERE c.CCIDReferredBy = r.CCID;
Khung nhìn (VIEW)
VIEW là một bảng ảo dựa trên kết quả của một câu lệnh SELECT. Nó hoạt động như một truy vấn đã được lưu lại, giúp đơn giản hóa các câu lệnh phức tạp và tái sử dụng chúng.
Ví dụ: Tạo một VIEW chứa các sản phẩm được bán nhiều hơn 3 món.
CREATE VIEW PRODUCTS_MORE_THAN_3_SOLD AS
SELECT ProductID, ProductName, ProductPrice
FROM PRODUCT
WHERE ProductID IN
(SELECT ProductID
FROM SOLDVIA
GROUP BY ProductID
HAVING SUM(NoOfItems) > 3);
Sau đó, bạn có thể truy vấn VIEW này như một bảng thông thường:
SELECT * FROM PRODUCTS_MORE_THAN_3_SOLD;
Các toán tử tập hợp (UNION, INTERSECT, EXCEPT/MINUS)
Các toán tử này dùng để kết hợp kết quả của hai hay nhiều câu lệnh SELECT. Điều kiện là các câu lệnh SELECT phải "tương thích" (cùng số lượng cột và kiểu dữ liệu tương ứng).
- UNION: Kết hợp kết quả và loại bỏ các hàng trùng lặp.
- INTERSECT: Chỉ trả về những hàng xuất hiện trong cả hai kết quả.
- EXCEPT (hoặc MINUS trên Oracle): Trả về những hàng có trong kết quả đầu tiên nhưng không có trong kết quả thứ hai.
Ví dụ: Lấy danh sách các sản phẩm hoặc được bán trên 3 món (PRODUCTS_MORE_THAN_3_SOLD) hoặc xuất hiện trong nhiều hơn 1 giao dịch (PRODUCTS_IN_MULTIPLE_TRNSC).
SELECT * FROM PRODUCTS_MORE_THAN_3_SOLD
UNION
SELECT * FROM PRODUCTS_IN_MULTIPLE_TRNSC;
Hỗ trợ tạo câu SQL bằng Generative AI
Trong thời đại công nghệ 4.0, việc sử dụng Generative AI (GenAI) đã trở thành một công cụ hữu ích trong việc hỗ trợ lập trình viên và nhà phân tích dữ liệu trong việc tạo ra các câu lệnh SQL. GenAI có khả năng hiểu ngữ cảnh và yêu cầu của người dùng, từ đó tự động tạo ra các câu lệnh SQL phù hợp.
Lợi ích của việc sử dụng GenAI trong SQL:
- Tiết kiệm thời gian: GenAI có thể tạo ra các câu lệnh SQL chỉ trong vài giây, giúp tiết kiệm thời gian cho lập trình viên.
- Giảm thiểu lỗi: GenAI có thể giúp giảm thiểu lỗi cú pháp và logic trong câu lệnh SQL, nhờ vào khả năng kiểm tra và tối ưu hóa.
- Hỗ trợ học tập: Người mới bắt đầu có thể học hỏi từ các câu lệnh mà GenAI tạo ra, từ đó nâng cao kỹ năng và hiểu biết về SQL.
- Tùy biến dễ dàng: GenAI có thể tạo ra các câu lệnh SQL tùy chỉnh dựa trên yêu cầu cụ thể của người dùng, bao gồm các điều kiện phức tạp hoặc các phép toán tập hợp.
Ví dụ: Bạn có thể yêu cầu GenAI tạo một câu lệnh SQL để lấy tất cả sản phẩm có giá lớn hơn 100 và thuộc nhà cung cấp có tên "Pacifica Gear". Đây là kết quả GenAI có thể trả về:
SELECT *
FROM PRODUCT
WHERE ProductPrice > 100 AND VendorID = (SELECT VendorID FROM VENDOR WHERE VendorName = 'Pacifica Gear');
Lời kết
SQL là một ngôn ngữ mạnh mẽ, linh hoạt và cực kỳ quan trọng trong thế giới dữ liệu. Việc nắm vững nó không chỉ là một lợi thế cạnh tranh mà còn là một yêu cầu cơ bản cho nhiều vị trí công việc. Con đường để trở thành chuyên gia SQL đòi hỏi sự thực hành liên tục. Hy vọng bài viết này đã cung cấp cho bạn một nền tảng vững chắc và một lộ trình rõ ràng để bắt đầu hành trình của mình.
Để dễ dàng ghi nhớ, dưới đây là bảng tóm tắt các lệnh SQL chính:
| Lệnh | Loại | Mục đích | Ví dụ cú pháp cơ bản |
|---|---|---|---|
| CREATE TABLE | DDL | Tạo một bảng mới trong cơ sở dữ liệu. | CREATE TABLE ten_bang (cot1 kieu_du_lieu, ...); |
| ALTER TABLE | DDL | Sửa đổi cấu trúc của một bảng đã có. | ALTER TABLE ten_bang ADD cot_moi kieu_du_lieu; |
| DROP TABLE | DDL | Xóa hoàn toàn một bảng. | DROP TABLE ten_bang; |
| INSERT INTO | DML | Thêm một hoặc nhiều hàng mới vào bảng. | INSERT INTO ten_bang (cot1, cot2) VALUES (gia_tri1, gia_tri2); |
| UPDATE | DML | Cập nhật dữ liệu trong các hàng đã có. | UPDATE ten_bang SET cot1 = gia_tri_moi WHERE dieu_kien; |
| DELETE | DML | Xóa các hàng khỏi bảng. | DELETE FROM ten_bang WHERE dieu_kien; |
| SELECT | DML | Truy vấn và lấy dữ liệu từ một hoặc nhiều bảng. | SELECT cot1, cot2 FROM ten_bang WHERE dieu_kien; |
| JOIN | DML | Kết hợp các hàng từ hai hoặc nhiều bảng. | SELECT ... FROM bang1 JOIN bang2 ON bang1.cot = bang2.cot; |
| GROUP BY | DML | Nhóm các hàng có cùng giá trị để tính toán tổng hợp. | SELECT cot, HAM_TONG_HOP(cot_khac) FROM ten_bang GROUP BY cot; |
| VIEW | DML | Tạo bảng ảo từ kết quả của một câu lệnh SELECT. | CREATE VIEW ten_view AS SELECT ...; |
| GenAI | Công nghệ hỗ trợ | Tạo câu lệnh SQL tự động dựa trên yêu cầu người dùng. | Hỗ trợ tạo câu lệnh SQL cho các truy vấn phức tạp. |
Hy vọng bài viết này sẽ giúp bạn có cái nhìn tổng quan và sâu sắc hơn về SQL, đồng thời khuyến khích bạn khám phá thêm các kỹ thuật và công cụ hỗ trợ trong quá trình làm việc với dữ liệu.