Chuyển tới nội dung chính

Chương 4: Ngôn ngữ SQL

Ngôn ngữ tiêu chuẩn giúp giao tiếp, quản lý và khai thác thông tin hiệu quả trên các hệ quản trị cơ sở dữ liệu quan hệ


1. Tổng quan về SQL

1.1. Giới thiệu

1.1.1. SQL là gì?

  • SQL là viết tắt của Structured Query Language (Ngôn ngữ truy vấn có cấu trúc). Đây là một ngôn ngữ cấp cao, được tiêu chuẩn hóa để người dùng có thể tương tác với các hệ quản trị cơ sở dữ liệu chỉ bằng cách đưa ra nội dung cần truy vấn.
  • SQL là ngôn ngữ nền tảng để làm việc với cơ sở dữ liệu quan hệ. Hầu hết mọi ứng dụng cần lưu trữ và truy xuất dữ liệu một cách có cấu trúc đều sử dụng SQL.
  • SQL hoạt động dựa trên mô hình CRUD (Create – Read – Update – Delete)

1.1.2. Lịch sử phát triển

  • Những năm 1970s, SQL được phát triển lần đầu tại IBM và có tên là SEQUEL (Structured English Query Language) nhằm cung cấp các thao tác để làm việc với System R – một DBMS nguyên mẫu của IBM.
  • Vào cuối những năm 1970s, SEQUEL được đổi tên thành SQL và từ đó đến hiện tại SQL có thể được phát âm theo 2 cách là se-quel hoặc s-q-l.
  • SQL đã trải qua nhiều phiên bản sửa đổi và cập nhật, tiêu biểu trong số đó là SQL1999, SQL2003, SQL2016...

1.2. Thuật ngữ và phân loại

1.2.1. Một số thuật ngữ phổ biến

Bảng (Table)

  • Bảng là cấu trúc lưu trữ chính trong cơ sở dữ liệu, bao gồm tập hợp các dữ liệu được tổ chức theo các hàng và các cột
  • Bảng thường có tên giống như tên quan hệ mà ta muốn lưu trữ. Ví dụ như SINHVIEN, SANPHAM, THIETBI,...
  • Ta có thể xem một bảng như một sheet riêng rẻ trong tệp Excel.

Cột (Column)

  • Cột (hay còn gọi là trường hay thuộc tính) là một thành phần dọc trong bảng, đại diện cho một loại thuộc tính cụ thể của quan hệ mà bảng lưu trữ. Mỗi cột có một tên và một kiểu dữ liệu duy nhất.
  • Ví dụ trong bảng SINHVIEN, có thể có các cột như MaSoSV, HoTen, NgaySinh,...

Hàng (Row)

  • Dòng (hay còn gọi là bản ghi hoặc bộ) là thành phần ngang trong bảng, chứa giá trị cụ thể cho từng cột trong bảng.
  • Ví dụ trong bảng SINHVIEN, một dòng sẽ lưu toàn bộ thông tin của một sinh viên cụ thể, chẳng hạn ('24521186', 'Nguyễn Chí Nguyên', '2006-03-10').

1.2.2. Phân loại SQL

Dựa vào chức năng và chương trình học môn Cơ sở dữ liệu hiện tại, có thể chia SQL thành 3 nhóm ngôn ngữ con chính:

  • Ngôn ngữ Định nghĩa Dữ liệu (Data Definition Language – DDL): Dùng để khai báo, định nghĩa và sửa đổi cấu trúc bảng, khai báo các mối quan hệ và các ràng buộc.
  • Ngôn ngữ Thao tác Dữ liệu (Data Manipulation Language – DML): Dùng để hiện thức thao tác với dữ liệu trên bảng như thêm, xóa, cập nhật dữ liệu.
  • Ngôn ngữ Điều khiển Dữ liệu (Data Control Language – DCL): Dùng để khai báo quyền bảo mật thông tin, cấp và thu hồi quyền khai thác trên cơ sở dữ liệu.

2. Ngôn ngữ định nghĩa dữ liệu

2.1. Kiểu dữ liệu và ràng buộc toàn vẹn

2.1.1. Một số kiểu dữ liệu phổ biến

Chuỗi ký tự

Kiểu dữ liệuMô tả
char(n), nchar(n)- Lưu chuỗi với độ dài cố định là nn. Nếu chuỗi nhập vào có ít hơn nn ký tự, DBMS sẽ tự động thêm các khoảng trắng vào cuối chuỗi để đạt đủ nn ký tự.
- Dùng nchar(n) khi chuỗi cần lưu chứa ký tự Unicode.
varchar(n), nvarchar(n)- Được sử dụng phổ biến.
- Lưu chuỗi với độ dài thay đổi với nn là độ dài tối đa. Nếu chuỗi nhập vào có số ký tự nhỏ hơn nn, DBMS sẽ lưu đúng chuỗi đó mà không tự lấp đầy bằng các khoảng trắng.
- Dùng nvarchar(n) khi chuỗi cần lưu chứa ký tự Unicode.

Kiểu số

Kiểu dữ liệuMô tả
tinyint, smallint, int, bigint- Lưu các dữ liệu là số nguyên với các kích thước lưu trữ khác nhau theo thứ tự là 1 byte, 2 bytes, 4 bytes và 8 bytes.
numeric(m, n), decimal(m, n), float, real- Lưu trữ dữ liệu là số thực.
- Thông thường, cả 4 kiểu dữ liệu này có thể dùng thay thế cho nhau. Kiểu numeric(m, n)decimal(m, n) để lưu số thập phân chính xác với mm tổng số chữ số và nn chữ số sau dấu phẩy.
smallmoney, money- Kiểu dữ liệu được tối ưu hóa cho việc lưu trữ tiền tệ. Thực chất là kiểu decimal nhưng cố định 4 chữ số sau dấu phẩy.
- Kích thước của smallmoney là 4 bytes và money là 8 bytes.

Kiểu thời gian

Kiểu dữ liệuMô tả
date, time, smalldatetime, datetime, datetime2- Lưu trữ thông tin về năm tháng ngày, giờ phút giây với các kích thước và độ chính xác khác nhau.
- Kiểu date chỉ lưu thông tin về ngày (Năm, tháng, ngày). Kiểu time chỉ lưu thông tin về giờ (Giờ, phút giờ). Kiểu smalldatetime, datetime, datetime2,... lưu thông tin cả về ngày và giờ.

Kiểu luận lý

Kiểu dữ liệuMô tả
bit
- Kiểu dữ liệu đơn giản nhất để lưu trữ giá trị logic Đúng/Sai.
- Phạm vi: 1 \rightarrow True, 0 \rightarrow False, NULL \rightarrow Undefined

2.1.2. Một số ràng buộc toàn vẹn phổ biến

Tên ràng buộcMô tả
Not null- Mặc định, một cột có thể giữ giá trị NULL.
- RBTV này bắt buộc một cột trong bảng phải có giá trị, không được để trống.
Unique- Đảm bảo mỗi giá trị trong một cột là duy nhất, không trùng lặp giá trị (Khóa tương đương).
Default- Thiết lập giá trị mặc định cho một cột. Giá trị mặc định này sẽ được gán cho các bộ nếu người dùng không nhập giá trị trên cột đó.
Check- Giới hạn phạm vi giá trị có thể nhận của một cột.
Primary key- Xác định khóa chính để đảm bảo tính duy nhất của mỗi bộ trong bản. Khóa chính phải là giá trị duy nhất, không trùng lặp và không thể là NULL.
- Mỗi bảng chỉ có duy nhất một khóa chính và có thể là một cột đơn hoặc kết hợp nhiều cột.
Foreign key- Xác định khóa ngoại, tham chiếu đến khóa chính của một bảng khác dùng để tạo mối liên kết giữa hai bảng và đảm bảo tính toàn vẹn tham chiếu.

Phân loại cấp độ ràng buộc:

  • Ràng buộc Primary key, Unique, Foreign keyCheck là ràng buộc cấp độ bảng, có thể áp dụng cho nhiều cột một lúc.
  • Ràng buộc Not null, Default là ràng buộc cấp độ cột, chỉ áp dụng một cột.

2.2. Tạo bảng

2.2.1. Khái quát

Để định nghĩa một bảng trong cơ sở dữ liệu, ta cần cung cấp các thông tin sau:

  • Tên bảng
  • Thông tin các thuộc tính bao gồm tên thuộc tính, kiểu dữ liệu và các ràng buộc toàn vẹn trên thuộc tính đó (nếu có).

Từ khóa: CREATE

Cú pháp:

CREATE TABLE <Tên_bảng>
(
Tên_cột_1 Kiểu_dữ_liệu [RBTV],
Tên_cột_2 Kiểu_dữ_liệu [RBTV],
...
[RBTV]
)
  • Lệnh đặt trong cặp dấu ngoặc vuông [...] là lệnh tùy chọn
  • SQL không phân biệt hoa thường.
  • Chỉ những RBTV cấp độ bảng mới có thể khai báo ở cuối câu lệnh CREATE TABLE.

2.2.2. Ví dụ

Cho lược đồ cơ sở dữ liệu Quản lý quán cà phê đơn giản như sau:
SANPHAM (MaSP, TenSP, DanhMuc, Size, DonGia)
KHACHHANG (MaKH, HoTenKH, SDT, Bac, DiemTichLuy, NgDangKy, NgHetHan)
NHANVIEN (MaNV, HoTenNV, GioiTinh, SDT, Email, BacLuong, CaLamViec)
HOADON (MaHD, NgayLap, MaNV, MaKH, TongTien)
CHITIETHD (MaHD MaSP, SoLuong)

Ví dụ 1: Tạo bảng KHACHHANG với mã khách hàng (MaKH) là khóa chính và họ tên khách hàng không được trống.

Ta có thể tạo bảng như sau:

CREATE TABLE KHACHHANG
(
MaKH char(4) Primary key,
HoTenKH nvarchar(50) Not null,
SDT char(10),
Bac nvarchar(10),
DiemTichLuy smallint,
NgDangKy datetime,
NgHetHan datetime
)

Hoặc cũng có thể làm như này:

CREATE TABLE KHACHHANG
(
MaKH char(4),
NgayLap nvarchar(50) Not null,
SDT char(10),
Bac nvarchar(10),
DiemTichLuy smallint,
NgDangKy datetime,
NgHetHan datetime,
Primary key (MaKH)
)
  • Vì sao trong cách làm thứ 2 lại không khai báo ràng buộc Not null như đã làm với Primary key? Đó là vì Not null là RBTV cấp độ cột nên bắt buộc phải được khai báo ngay khi cột đó được khai báo.

Ví dụ 2: Tạo bảng HOADON với mã nhân viên (MaNV) và mã khách hàng (MaKH) là các khóa ngoại tham chiếu lần lượt đến khóa chính của bảng NHANVIEN và bảng KHACHHANG.

Tương tự như trên, ta cũng có thể làm theo 2 cách như sau,

Cách 1:

CREATE TABLE HOADON
(
MaHD char(4) Primary key,
NgayLap datetime,
MaNV char(4) Foreign key references NHANVIEN(MaNV),
MaKH char(4) Foreign key references KHACHHANG(MaKH),
TongTien money
)

Cách 2:

CREATE TABLE HOADON
(
MaHD char(4),
NgayLap datetime,
MaNV char(4),
MaKH char(4),
TongTien money,
Primary key (MaHD),
Foreign key (MaNV) references NHANVIEN(MaNV),
Foreign key (MaKH) references KHACHHANG(MaKH)
)

Ví dụ 3 Tạo bảng CHITIETHD với khóa chính gồm 2 cột là mã hóa đơn (MaHD) và mã sản phẩm (MaSP) đồng thời cũng là khóa ngoại tham chiếu đến các khóa chính tương ứng của bảng HOADON và bảng SANPHAM.

Cách làm sau đây là cách làm SAI:

CREATE TABLE CHITIETHD
(
MaHD char(4) Primary key,
MaSP char(4) Primary key,
SoLuong smallint,
Foreign key (MaHD) references HOADON(MaHD),
Foreign key (MaSP) references SANPHAM(MaSP)
)
  • Vì sao cách làm trên lại sai? Đó là bởi vì mỗi bảng chỉ có duy nhất một khóa chính (Primary key). Nếu ta khai báo khóa chính trên mỗi dòng DBMS sẽ hiểu cả hai cột MaHD và MaSP đều cùng là khóa chính và báo lỗi. Cách hiểu đúng ở đây là khóa chính gồm hai cột MaHD và MaSP không phải cả hai cột MaHD và MaSP đều là khóa chính. MaHD và MaSP là một phần của khóa chính.

Cách làm ĐÚNG:

CREATE TABLE CHITIETHD
(
MaHD char(4),
MaSP char(4),
SoLuong smallint,
Primary key (MaHD, MaSP),
Foreign key (MaHD) references HOADON(MaHD),
Foreign key (MaSP) references SANPHAM(MaSP)
)

2.3. Sửa đổi cấu trúc bảng

2.3.1. Khái quát

Có nhiều thao tác sửa đổi cấu trúc của một bảng và được phân thành các thao tác chính như sau:

  • Thêm cột vào bảng;
  • Sửa kiểu dữ liệu trên cột;
  • Xóa cột khỏi bảng;
  • Thêm ràng buộc toàn vẹn;
  • Xóa ràng buộc toàn vẹn.

Từ khóa: ALTER

Cú pháp chung:

ALTER TABLE Tên_bảng
Cú_pháp_thực_hiện_của_thao_tác

Mỗi loại thao tác sửa đổi cấu trúc bảng lại có cú pháp lệnh khác nhau, ta sẽ tìm hiểu từng thao tác.

2.3.2. Thêm thuộc tính vào bảng

Cú pháp:

ALTER TABLE Tên_bảng
ADD Tên_cột Kiểu_dữ_liệu

Ví dụ:
Thêm cột ngày vào làm việc (NgLamViec) vào bảng NHANVIEN

ALTER TABLE NHANVIEN
ADD NgLamViec DATETIME

Thêm thuộc tính mã nhân viên (MaNV) vào bảng NHANVIEN và định nghĩa MaNV là khóa chính.

ALTER TABLE NHANVIEN
ADD MaNV char(4) NOT NULL PRIMARY KEY

2.3.3. Sửa kiểu dữ liệu trên thuộc tính

Cú pháp:

ALTER TABLE Tên_bảng
ALTER COLUMN Tên_cột Kiểu_dữ_liệu_mới
  • Không phải sửa thành kiểu dữ liệu nào cũng được mà phải đảm bảo điều kiện về độ dài dữ liệu, khả năng chuyển đổi và tương thích dữ liệu, chẳng hạn không thể chuyển kiểu chuỗi ký tự thành kiểu số.
  • Ngoài ra, khi sửa kiểu dữ liệu phải đảm bảo điều kiện của các RBTV nếu có (Not null, Check, Foreign key...) Ví dụ:
    Sửa kiểu dữ liệu của cột NgLamViec thuộc bảng NHANVIEN thành kiểu smalldatetime.
ALTER TABLE NHANVIEN
ALTER COLUMN NgLamViec SMALLDATETIME

Sửa kiểu dữ liệu của cột NgLamViec trong bảng NHANVIEN sao cho nó không nhận giá trị NULL

ALTER TABLE NHANVIEN
ALTER COLUMN NgLamViec SMALLDATETIME NOT NULL

2.3.4. Xóa cột khỏi hàng

Cú pháp:

ALTER TABLE Tên_bảng 
DROP COLUMN Tên_cột
  • Chỉ có thể xóa cột không có ràng buộc phụ thuộc: Không là một phần của khóa chính, khóa tương đương (unique) hoặc check; không được tham chiếu bởi khóa ngoại từ bảng khác.

Ví dụ:
Xóa cột NgLamViec khỏi bảng NHANVIEN

ALTER TABLE NHANVIEN
DROP COLUMN NgLamViec

2.3.5. Thêm ràng buộc toàn vẹn

Cú pháp:

ALTER TABLE Tên_bảng
ADD CONSTRAINT Tên_RBTV Cú_pháp_của_RBTV
  • Ta chỉ có thể thêm các RBTV ở cấp độ bảng và Default.
  • Mỗi RBTV có các cú pháp lệnh khác nhau:
Loại ràng buộcCú pháp lệnh
Primary keyPrimary key (Tên_cột)
Foreign keyForeign key (Tên_cột) references Tên_bảng(Tên_cột_khóa_chính)
CheckCheck (Điều_kiện_kiểm_tra)
UniqueUnique (Tên_cột)
DefaultDefault Giá_trị_mặc_định> for Ten_cot

Ví dụ 1:
a. Thêm ràng buộc mã nhân viên (MaNV) là khóa chính của bảng NHANVIEN

ALTER TABLE NHANVIEN 
ADD CONSTRAINT PK_NhanVien PRIMARY KEY (MaNV)

b. Thêm ràng buộc khóa chính cho bảng CHITIETHD bao gồm hai thuộc tính là mã hóa đơn (MaHD) và mã sản phẩm (MaSP)

ALTER TABLE CHITIETHD 
ADD CONSTRAINT PK_ChiTietHD PRIMARY KEY (MaHD, MaSP)
  • Khi thêm ràng buộc khóa chính, phải đảm bảo cột được thêm hoặc các cột là thành phần của khóa chính được thêm đã tồn tại trong bảng và phải được định nghĩa là Not null.

Ví dụ 2:
Thêm ràng buộc khóa ngoại giữa bảng CHITIETHD và bảng SANPHAM, khóa ngoại thuộc bảng CHITIETHD và tham chiếu đến SANPHAM là MaSP.

ALTER TABLE CHITIETHD 
ADD CONSTRAINT FK_CT_SP FOREIGN KEY (MaSP) REFERENCES SANPHAM(MaSP)
  • Khi thêm ràng buộc khóa ngoại, cần đảm bảo tương thích kiểu dữ liệu giữa thuộc tính khóa ngoại và thuộc tính được tham chiếu đến. Cần đảm bảo thuộc tính được tham chiếu đến của một bảng chính là khóa chính của bảng đó.

Ví dụ 3:
Thêm ràng buộc bậc lương (BacLuong) của nhân viên của bảng NHANVIEN phải lớn hơn 0.

ALTER TABLE NHANVIEN 
ADD CONSTRAINT CK_NV_BacLuong CHECK (BacLuong > 0)

Thêm ràng buộc giới tính (GioiTinh) của nhân viên là nam hoặc nữ trong bảng NHANVIEN.

ALTER TABLE NHANVIEN 
ADD CONSTRAINT CK_NV_GioiTinh CHECK (GioiTinh IN (‘Nam’, N’Nữ’))

Ví dụ 4:
Thêm ràng buộc đảm bảo số điện thoại (SDT) của mỗi nhân viên là khác nhau trong bảng NHANVIEN.

ALTER TABLE NHANVIEN 
ADD CONSTRAINT UQ_NV_SDT UNIQUE (SDT)

Ví dụ 5:
Thêm ràng buộc đặt giá trị mặc định cho bậc lương (BacLuong) của nhân viên của NHANVIEN là 1.

ALTER TABLE NHANVIEN 
ADD CONSTRAINT DF_NV_BacLuong DEFAULT 1 FOR BacLuong

2.3.6. Xóa ràng buộc toàn vẹn

Cú pháp:

ALTER TABLE <Tên_bảng> 
DROP CONSTRAINT <Tên_RBTV>
  • Khi xóa một RBTV, cần đảm bảo đã xóa hết các khóa ngoại tham chiếu đến nó.

Ví dụ:
Xóa ràng buộc giới tính (GioiTinh) của nhân viên phải là nam hay nữ trong bảng NHANVIEN

ALTER TABLE NHANVIEN 
DROP CONSTRAINT CK_NV_GioiTinh

Xóa ràng buộc số điện thoại của mỗi nhân viên là khác nhau trong bảng NHANVIEN

ALTER TABLE NHANVIEN 
DROP CONSTRAINT UQ_NV_SDT

2.4. Xóa bảng

2.4.1. Khái quát

Từ khóa: DROP

Cú pháp:

DROP TABLE <Tên_bảng>
  • Khi xóa một bảng cần đảm bảo đã xóa hết các ràng buộc là khóa ngoại tham chiếu tới bảng đó.

2.4.2. Ví dụ

Xóa bảng NHANVIEN

DROP TABLE NHANVIEN

3. Ngôn ngữ thao tác dữ liệu

3.1. Thêm dữ liệu vào bảng

3.1.1. Khái quát

Để thêm dữ liệu vào một bảng, ta cần xác định

  • Tên bảng cần thêm dữ liệu;
  • Danh sách các cột cần thêm dữ liệu của bảng;
  • Danh sách các giá trị được thêm tương ứng với các cột.

Từ khóa: INSERT

Cú pháp:

INSERT INTO <Tên_bảng> [(<Danh_sách các cột>)]
VALUES {(<Danh_sách_các_giá_trị>)}
  • Khi không truyền vào danh sách các cột cần thêm, mặc định sẽ thêm dữ liệu vào tất cả các cột.
  • Có thêm thêm một hoặc nhiều dòng dữ liệu.
  • Thứ tự các giá trị trong dòng dữ liệu được thêm phải tương ứng với danh sách các cột được thêm, và cần đảm bảo về kiểu dữ liệu.
  • Có thể thêm giá trị NULL ở những cột không phải là khóa chính và không là Not null.
  • Không thể thêm dữ liệu nếu vi phạm các RBTV: Primary key, Foreign key, Not null.

3.1.2. Ví dụ

Ví dụ 1: Thêm một dòng dữ liệu
Thêm dữ liệu một sản phẩm có mã sản phẩm(MaSP) là SP01, tên sản phẩm (TenSP) là Espresso, thuộc danh mục (DanhMuc) Cà phê, Size S và giá (DonGia) là 39.000 VND vào bảng SANPHAM.

INSERT INTO SANPHAM (MaSP, TenSP, DanhMuc, Size, DonGia)
VALUES (‘SP01’, ‘Espresso’, N’Cà phê’, ‘S’, 39000)

Do các giá trị của dữ liệu được thêm vào tất cả các cột của bảng SANPHAM nên ta có thể viết một cách ngầm định (Không khuyên dùng):

INSERT INTO SANPHAM
VALUES (‘SP01’, ‘Espresso’, N’Cà phê’, ‘S’, 39000)

Ví dụ 2: Thêm nhiều dòng dữ liệu

INSERT INTO SANPHAM
VALUES
(‘SP01’, ‘Espresso’, N’Cà phê’, ‘S’, 29000),
(‘SP02’, ‘Matcha latte’, ‘Latte’, ‘M’, 35000),
(‘SP03’, N’Sữa tươi trân châu đường đen’, N’Sữa tươi’, ‘L’, 35000)

3.2. Cập nhật dữ liệu trên bảng

3.2.1. Khái quát

Để cập nhật 1 hay nhiều dòng dữ liệu trên bảng

Từ khóa: UPDATE

Cú pháp:

UPDATE <Tên bảng>
SET {<Thuộc tính cần sửa> = <Giá trị mới>}
[WHERE <Điều kiện chọn>]
  • Câu lệnh WHERE sẽ chọn ra những dòng thỏa điều kiện chọn để cập nhật dữ liệu cho những dòng đó.
  • Nếu không có WHERE, toàn bộ dòng trong bảng sẽ được cập nhật giá trị mới.

3.2.2. Ví dụ

Ví dụ 1: Cập nhật một cột dữ liệu
Cập nhật bậc (Bac) cho những khách hàng có điểm tích lũy đạt 1000 điểm trở lên là ‘Vàng’ trong bảng KHACHHANG.

UPDATE KHACHHANG
SET Bac = N’Vàng’
WHERE DiemTichLuy >= 1000

Ví dụ 2: Cập nhật nhiều cột dữ liệu
Cập nhật bậc (Bac) cho những khách hàng có điểm tích lũy đạt 1000 điểm trở lên là ‘Vàng’ và đặt ngày hết hạn thành viên (NgHetHan) thành 1/1/2026 trong bảng KHACHHANG.

UPDATE KHACHHANG
SET
Bac = N’Vàng’,
NgHetHan =2026-1-1
WHERE DiemTichLuy >= 1000

3.3. Xóa dữ liệu khỏi bảng

3.3.1. Khái quát

Dùng để xóa một hay nhiều dòng dữ liệu trên bảng

Từ khóa: DELETE

Cú pháp:

DELETE FROM <Tên bảng>
[WHERE <Điều kiện chọn>].
  • Câu lệnh WHERE sẽ chọn ra những dòng thỏa điều kiện chọn để xóa những dòng đó.
  • Nếu không có WHERE, toàn bộ dòng trong bảng sẽ bị xóa hoàn toàn.

3.2.2. Ví dụ

Ví dụ 1: Xóa toàn bộ dữ liệu

Xóa toàn bộ dữ liệu trong bảng SANPHAM

DELETE FROM SANPHAM

Ví dụ 2: Xóa có chọn lọc

Xóa những dòng dữ liệu trong bảng SANPHAM thỏa mãn đơn giá (DonGia) lớn hơn 50000 và có Size là ‘L’

DELETE FROM SANPHAM
WHERE DonGia > 50000 AND Size = ‘L’

4. Ngôn ngữ truy vấn dữ liệu

4.1. Cấu trúc câu lệnh truy vấn.

    SELECT [DISTINCT] <Danh sách các thuộc tính / hàm>
FROM <Danh sách các bảng>
[WHERE <Điều kiện>]
[GROUP BY <Danh sách thuộc tính gom nhóm>]
[HAVING <Điều kiện trên nhóm>]
[ORDER BY {<Thuộc tính sắp xếp> ASC / DESC }]
  • Tên các thuộc tính/hàm cần hiển thị ở két quả.
  • Các thuộc tính/hàm ngăn cách nhau bởi dấu ,.
  • Sử dụng dấu * nếu muốn xem tất cả các cột.

<Danh sách các bảng>

  • Tên các bảng mà ta sẽ lấy dữ liệu.
  • Nếu lấy dữ liệu trên nhiều bảng, thường sẽ sử dụng JOIN để kết các bảng.

<Điều kiện>

  • Sử dụng các toán tử so sánh, toán tử logic hoặc các biểu thức Boolean để lọc dữ liệu, xác định những dòng nào sẽ được chọn.

<Danh sách các thuộc tính gom nhóm>

  • Gom các dòng có giá trị giống nhau thành một nhóm theo những thuộc tính trong danh sách.
  • Các thuộc tính ngăn cách nhau bởi dấu ,.

<Điểu kiện trên nhóm>

  • Chức năng tương tự như <Điều kiện> nhưng chỉ lọc dữ liệu sau khi đã gom nhóm.

<Thuộc tính sắp xếp>

  • Sắp xếp kết quả theo thứ tự nào dựa trên thuộc tính sắp xếp.
  • ASC là sắp xếp tăng dần (A-Z, 0-9), DESC là sắp xếp giảm dần (Z-A, 9-0).

4.2. Các toán tử, các hàm

4.2.1. Các toán tử so sánh

TOÁN TỬCHỨC NĂNG
= > < >= <= <>Dùng để so sánh các giá trị của hai biểu thức.
BETWEENKiểm tra một giá trị có nằm trong một khoảng nhất định hay không.
IS NULL, IS NOT NULLSo sánh một giá trị với NULL.
LIKE ‘%’, LIKE ‘_’So sánh chuỗi với một mẫu nhất định.% đại diện cho một chuỗi ký tự bất kỳ._ đại diện cho đúng 1 ký tự bất kỳ.
IN, NOT INKiểm tra một giá trị có nằm trong một tập hợp cụ thể hay không
EXISTS, NOT EXISTSThường dùng với Subquery, kiểm tra xem subquery có trả về dòng nào hay không.
SOME, ANY, ALLSo sánh một giá trị với một danh sách giá trị.

4.2.2. Các toán tử logic

ANDLọc ra các dòng thỏa mãn cả hai biểu thức.
ORLọc ra các dòng thỏa mãn ít nhất một trong hai biểu thức.
  • Toán tử AND sẽ được ưu tiên chạy trước toán tử OR nên bất cứ khi nào dùng chung ANDOR, hãy dùng dấu ngoặc đơn (...) để đảm bảo kết quả đúng

4.2.3. Một số hàm xử lý chuỗi, số, các hàm xử lý ngày và các hàm tính toán trên nhóm

  • Một số hàm xử lý trên chuỗi: SUBSTRING(), LEFT(), RIGHT(), UPPER(), LOWER(), CONCAT(), REPLACE(),…
  • Một số hàm xử lý trên số: ABS(), SQRT(), POWER(), ROUND(),…
  • Các hàm xử lý trên ngày: DAY(), MONTH(), YEAR().
  • Các hàm tính toán trên nhóm: MAX(), MIN(), AVG(), SUM(), COUNT().

4.3. Truy vấn cơ bản

4.3.1. Cú pháp

SELECT [DISTINCT] <Danh sách các thuộc tính / hàm>
FROM <Danh sách các bảng>
[WHERE <Điều kiện>]
[ORDER BY {<Thuộc tính sắp xếp> ASC / DESC }]

4.3.2. Ví dụ

Ví dụ 1: Hiển thị các cột dữ liệu trên bảng
Liệt kê mã sản phẩm (MaSP) và tên sản phẩm (TenSP) của tất cả các sản phẩm trong bảng SANPHAM.

SELECT MaSP, TenSP
FROM SANPHAM

Ví dụ 2: Sử dụng WHERE để lọc dữ liệu
Liệt kê mã sản phẩm (MaSP) và tên sản phẩm (TenSP) của tất cả các sản phẩm trong bảng SANPHAM có đơn giá (DonGia) lớn hơn 30.000đ.

SELECT MaSP, TenSP
FROM SANPHAM
WHERE DonGia > 30000

Ví dụ 3: Sử dụng * để chọn tất cả các thuộc tính
Liệt kê tất cả thông tin của các sản phẩm có đơn giá (DonGia) lớn hơn 30.000đ.

SELECT *
FROM SANPHAM
WHERE DonGia > 30000

Ví dụ 4: Sử dụng biểu thức tính toán để hiển thị
Liệt kê mã sản phẩm (MaSP), tên sản phẩm (TenSP) và đơn giá dự tính sau khi tăng 10% của tất cả sản phẩm thuộc danh mục (DanhMuc) Latte.

SELECT MaSP, TenSP, DonGia * 1.1 AS ‘DonGiaDuTinh’
FROM SANPHAM
WHERE DanhMuc = ‘Latte’

Ví dụ 5: Sử dụng hàm để hiển thị
Liệt kê tất cả thông tin và năm lập hóa đơn của các hóa đơn có tổng tiền không dưới 100.000đ.

SELECT *,  YEAR(NgayLap) AS ‘Nam lap hoa don’
FROM HOADON
WHERE TongTien >= 100000

Ví dụ 6: Sử dụng ORDER BY để sắp xếp kết quả hiển thị
Liệt kê mã hóa đơn (MaHD) và tổng tiền (TongTien) của các hóa đơn được lập trong tháng 10, sắp xếp giảm dần theo tổng tiền.

SELECT MaHD, TongTien
FROM HOADON
WHERE MONTH(NgayLap) = 10
ORDER BY TongTien DESC

Liệt kê mã hóa đơn (MaHD) và tổng tiền (TongTien) của các hóa đơn được lập trong năm 2025, sắp xếp giảm dần theo tổng tiền, và tăng dần theo mã hóa đơn.

SELECT MaHD, TongTien
FROM HOADON
WHERE YEAR(NgayLap) = 2025
ORDER BY TongTien DESC, MaHD ASC

Ví dụ 7: Sử dụng DISTINCT để loại bỏ các dòng dữ liệu trùng nhau trong kết quả.
Liệt kê các danh mục sản phẩm (DanhMuc) hiện đang có, sắp xếp các danh mục tăng dần theo bảng chữ cái.

SELECT DISTINCT DanhMuc AS ‘Danh Muc San Pham’
FROM SANPHAM
ORDER BY DanhMuc ASC

Ví dụ 8: Sử dụng toán tử so sánh, toán tử logic trong điều kiện chọn
Liệt kê mã sản phẩm (MaSP), size của những sản phẩm thuộc danh mục (DanhMuc) cà phê và có giá bán (DonGia) lớn hơn 20.000đ.

SELECT MaSP, Size
FROM SANPHAM
WHERE DanhMuc = N’Cà phê’ AND DonGia > 20000

Liệt kê mã sản phẩm, tên sản phẩm, size của các sản phẩm có giá bán từ 20.000đ đến 50.000đ.

SELECT MaSP, TenSP, Size
FROM SANPHAM
WHERE DonGia >= 20000 AND DonGia <= 50000

Hoặc:

SELECT MaSP, TenSP, Size
FROM SANPHAM
WHERE DonGia BETWEEN 20000 AND 50000

Liệt kê mã sản phẩm, tên sản phẩm, size của các sản phẩm thuộc danh mục trà hoặc cà phê hoặc latte.

FROM SANPHAM
WHERE DanhMuc = N’Trà’ OR DanhMuc = N’Cà phê’ OR DanhMuc = N‘Latte’

Hoặc:

SELECT MaSP, TenSP, Size
FROM SANPHAM
WHERE DanhMuc IN (N’Trà’, N’Cà phê’, N‘Latte’)

Ví dụ 9: Sử dụng JOIN (INNER JOIN) để kết các bảng.
Liệt kê mã hóa đơn (MaHD), tổng tiền (TongTien) của các hóa đơn được xử lý bởi nhân viên có tên Nguyễn Văn A.

SELECT MaHD, TongTien
FROM HOADON
JOIN NHANVIEN ON NHANVIEN.MaNV = HOADON.MaNV
WHERE TenNV = N’Nguyễn Văn A’

Liệt kê mã hóa đơn (MaHD), mã sản phẩm (MaSP), tên sản phẩm (TenSP) của những, ngày lập hóa đơn (NgayLap) được tạo trong tháng 10 và xử lý bởi nhân viên có mã là NV01.

SELECT HD.MaHD, SP.MaSP, TenSP, NgayLap
FROM HOADON HD
JOIN CHITIETHD CT ON CT.MaHD = HD.MaHD
JOIN SANPHAM SP ON SP.MaSP = CT.MaSP
WHERE MONTH(NgayLap) = 10 AND MaNV = ‘NV01’

4.4. Truy vấn sử dụng phép toán tập hợp

4.4.1. Cú pháp

(Câu truy vấn 1)
<UNION/INTERSECT/EXCEPT>
(Câu truy vấn 2)
  • Phép hội UNION sẽ lấy tất cả các dòng dữ liệu xuất hiện ở kết quả của ít nhất một câu truy vấn và loại bỏ các dòng dữ liệu bị trùng nhau.
  • Phép giao INTERSECT sẽ lấy các dòng dữ liệu xuất hiện ở kết quả của tất cả câu truy vấn.
  • Phép trừ EXCEPT sẽ lấy các dòng dữ liệu xuất hiện ở kết quả của câu truy vấn thứ nhất nhưng không xuất hiện ở kết quả của câu truy vấn thứ hai.
  • Nếu muốn sử dụng các phép toán tập hợp, cần đảm bảo điều kiện khả hợp, các cột dữ liệu được chọn ở cả hai câu truy vấn giống nhau hoàn toàn.

4.4.2. Ví dụ

Ví dụ 1: Phép hội
Liệt kê mã nhân viên (MaNV), họ tên (HoTenNV) của những nhân viên làm việc ở ca (CaLamViec) 1 hoặc 2.

SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 1
UNION
SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 2
SELECT HoTenKH AS HoTen, SDT
FROM KHACHHANG
UNION
SELECT HoTenNV AS HoTen, SDT
FROM NHANVIEN

Ví dụ 2: Phép giao
Liệt kê mã nhân viên (MaNV), họ tên (HoTenNV) của những nhân viên làm việc ở ca (CaLamViec) 1 và 2.

Đây là cách làm sai:

SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 1 AND CaLamViec = 2

Cách làm đúng sử dụng phép toán tập hợp:

SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 1
INTERSECT
SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 2

Liệt kê họ tên và số điện thoại của những người vừa là nhân viên vừa là khách hàng.

SELECT HoTenKH AS HoTen, SDT
FROM KHACHHANG
INTERSECT
SELECT HoTenNV AS HoTen, SDT
FROM NHANVIEN

Ví dụ 3: Phép trừ
Liệt kê mã nhân viên (MaNV), họ tên (HoTenNV) của những nhân viên làm việc ở ca (CaLamViec) 1 nhưng không làm việc ở ca 2.

SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 1
EXCEPT
SELECT MaNV, HoTenNV
FROM NHANVIEN

Liệt kê họ tên và số điện thoại của những người là nhân viên nhưng không phải là khách hàng.

SELECT HoTenNV AS HoTen, SDT
FROM NHANVIEN
EXCEPT
SELECT HoTenKH AS HoTen, SDT
FROM KHACHHANG

4.5. Truy vấn lồng

4.5.1 Cú pháp

SELECT [DISTINCT] <Danh sách các thuộc tính / hàm>
FROM <Danh sách các bảng>
WHERE <Điều kiện> (<Câu truy vấn con>)
  • Câu truy vấn con hoạt động như một khối cung cấp dữ liệu hoặc điều kiện cho câu truy vấn chính mà nó nằm bên trong.
  • <Điều kiện>: Ngoài các toán tử, phép toán so sánh thông thường, có thể dùng [NOT] EXISTS (<Truy vấn con>) để thực hiện truy vấn lồng. EXISTS kiểm tra sự tồn tại của bất kỳ dòng nào thỏa mãn điều kiện của truy vấn con, trả về TRUE nếu kết quả của truy vấn con có ít nhất một dòng và trả về FALSE nếu ngược lại.
  • Có thể sử dụng phủ định kép (kết hợp NOT EXISTS và truy vấn lồng 2 lần) để hiện thực phép chia quan hệ:
SELECT [DISTINCT] <Danh sách các thuộc tính / hàm>
FROM <Danh sách các bảng>
WHERE <Điều kiện> NOT EXISTS (
SELECT *
FROM <Danh sách các bảng>
WHERE <Điều kiện> NOT EXISTS (
SELECT *
FROM <Danh sách các bảng>
WHERE <Điều kiện>)

4.5.2. Ví dụ

Ví dụ 1: Truy vấn lồng cơ bản
Liệt kê mã sản phẩm (MaSP), Tên sản phẩm (TenSP) của những sản phẩm có giá bán cao hơn tất cả các sản phẩm thuộc danh mục Latte.

SELECT MaSP, TenSP
FROM SANPHAM
WHERE DonGia > ALL (
SELECT DonGia
FROM SANPHAM
WHERE DanhMuc = N‘Latte’)

Liệt kê mã sản phẩm (MaSP), Tên sản phẩm (TenSP) của những sản phẩm có giá bán cao hơn ít nhất sản phẩm thuộc danh mục Latte.

SELECT MaSP, TenSP
FROM SANPHAM
WHERE DonGia > ANY (
SELECT DonGia
FROM SANPHAM
WHERE DanhMuc = N‘Latte’)

Ví dụ 2: Sử dụng truy vấn lồng để thực hiện truy vấn với phép toán tập hợp
Liệt kê mã nhân viên (MaNV), họ tên (HoTenNV) của những nhân viên làm việc ở cả hai ca (CaLamViec) 1 và 2.

SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 1 AND MaNV IN (
SELECT MaNV
FROM NHANVIEN
WHERE CaLamViec = 2)

Hoặc:

SELECT MaNV, HoTenNV
FROM NHANVIEN NV1
WHERE CaLamViec = 1 AND EXITSTS (
SELECT *
FROM NHANVIEN NV2
WHERE CaLamViec = 2
AND NV2.MaNV = NV1.MaNV)

Liệt kê mã nhân viên (MaNV), họ tên (HoTenNV) của những nhân viên làm việc ở ca (CaLamViec) 1 nhưng không làm việc ở ca 2.

SELECT MaNV, HoTenNV
FROM NHANVIEN
WHERE CaLamViec = 1 AND MaNV NOT IN (
SELECT MaNV
FROM NHANVIEN
WHERE CaLamViec = 2)

Hoặc:

SELECT MaNV, HoTenNV
FROM NHANVIEN NV1
WHERE CaLamViec = 1 AND NOT EXITSTS (
SELECT *
FROM NHANVIEN NV2
WHERE CaLamViec = 2
AND NV2.MaNV = NV1.MaNV)

Ví dụ 3: Hiện thực “phép chia” bằng cách phủ định kép
Tìm khách hàng đã mua tất cả các sản phẩm
=> Tìm khách hàng không thuộc danh sách các khách hàng không mua ít nhất một sản phẩm.

SELECT KH.MaKH
FROM KHACHHANG KH
WHERE NOT EXISTS (
SELECT *
FROM SANPHAM SP
WHERE NOT EXISTS (
SELECT *
FROM HOADON HD
JOIN CHITIETHD CT ON CT.MaHD = HD.MaHD
WHERE CT.MaSP = SP.MaSP
AND KH.MaKH = HD.MaKH
)
)

4.6. Truy vấn sử dụng hàm tính toán trên nhóm

4.6.1 Cú pháp

SELECT [DISTINCT] <Danh sách các thuộc tính / hàm>
FROM <Danh sách các bảng>
[WHERE <Điều kiện>]
[GROUP BY <Danh sách thuộc tính gom nhóm>]
[HAVING <Điều kiện trên nhóm>]
[ORDER BY {<Thuộc tính sắp xếp> ASC / DESC }]
  • Đây là kỹ thuật dùng để tóm tắt dữ liệu theo các danh mục hoặc tiêu chí cụ thể, mục đích để trả lời các câu hỏi thống kê.
  • Hàm tính toán trên nhóm được áp dụng cho từng thuộc tính riêng rẽ và sẽ trả về một giá trị đơn duy nhất trên nhóm đó.
  • Các hàm tính toán trên nhóm:
HàmChức năng
COUNT()Đếm số lượng dòng dữ liệu
SUM()Tính tổng các giá trị số
AVG()Tính giá trị trung bình
MAX()Tìm giá trị lớn nhất
MIN()Tìm giá trị nhỏ nhất

4.6.2. Ví dụ

Ví dụ 1: Sử dụng hàm tính toán trên nhóm để hiển thị kết quả
Tìm đơn giá cao nhất, đơn giá thấp nhất, đơn giá trung bình của các sản phẩm trong bảng SANPHAM

SELECT 
MAX(DonGia) AS N’Đơn giá cao nhất’,
MIN(DonGia) AS N’Đơn giá thấp nhất’,
AVG(DonGia) AS N’Đơn giá trung bình’
FROM SANPHAM

Tìm đơn giá cao nhất, đơn giá thấp nhất, đơn giá trung bình của các sản phẩm thuộc danh mục cà phê trong bảng SANPHAM

SELECT 
MAX(DonGia) AS N’Đơn giá cao nhất’,
MIN(DonGia) AS N’Đơn giá thấp nhất’,
AVG(DonGia) AS N’Đơn giá trung bình’
FROM SANPHAM
WHERE DanhMuc = N’Cà phê’

Ví dụ 2: Gom nhóm
Thống kê số lượng sản phẩm của mỗi danh mục, hiển thị tên các danh mục.

SELECT DanhMuc, COUNT(MaSP) AS SoSP
FROM SANPHAM
GROUP BY DanhMuc

Liệt kê tên danh mục và số lượng sản phẩm của mỗi danh mục lớn hơn 10, sắp xếp theo số sản phẩm giảm dần.

SELECT DanhMuc, COUNT(MaSP) AS SoSP
FROM SANPHAM
GROUP BY DanhMuc
HAVING COUNT(MaSP) > 10
ORDER BY COUNT(MaSP) DESC

Ví dụ 3: Sử dụng TOP để lấy giá trị
Tìm tên và số lượng sản phẩm của 3 danh mục có số lượng sản phẩm nhiều nhất.

SELECT TOP 3 DanhMuc, COUNT(MaSP) AS SoSP
FROM SANPHAM
GROUP BY DanhMuc
ORDER BY COUNT(MaSP) DESC
  • TOP n chỉ lấy đúng n dòng đầu tiên của bảng tìm được . Sử dụng từ khóa WITH TIES nếu muốn lấy chính xác các dòng thỏa điều kiện có số sản phẩm lớn nhất (hoặc thấp nhất).

Tìm tên và số lượng sản phẩm của các danh mục có số lượng sản phẩm ít nhất.

SELECT TOP 1 WITH TIES DanhMuc, COUNT(MaSP) AS SoSP
FROM SANPHAM
GROUP BY DanhMuc
ORDER BY COUNT(MaSP) ASC

Hoặc ta có thể sử dụng truy vấn lồng

SELECT DanhMuc, COUNT(MaSP) AS SoSP
FROM SANPHAM
GROUP BY DanhMuc
HAVING COUNT(MaSP) <= ALL(
SELECT COUNT(MaSP)
FROM SANPHAM
GROUP BY DanhMuc
)

4.7. Truy vấn sử dụng phép kết ngoài

4.7.1 Cú pháp

<Tên bảng 1>
<Lệnh kết ngoài> ON <Thuộc tính kết 1> = <Thuộc tính kết 2>
<Tên bảng 2>
  • Lệnh kết ngoài: LEFT OUTER JOIN (Kết trái), RIGHT OUTER JOIN (Kết phải), FULL OUTER JOIN (Kết đầy đủ.
  • Sử dụng phép kết ngoài trong một số trường hợp để tối ưu truy vấn và hạn chế bỏ sót dữ liệu.

4.7.2. Ví dụ

Ví dụ 1:
Cho biết mã sản phẩm, tên sản phẩm và đơn giá của những sản phẩm chưa từng được mua.

SELECT SP.MaSP, TenSP, DonGia
FROM SANPHAM SP
LEFT OUTER JOIN CHITIETHD CT ON CT.MaSP = SP.MaSP
WHERE MaHD IS NULL

Ví dụ 2:
Liệt kê mã sản phẩm, tên sản phẩm, đơn giá của các sản phẩm và mã hóa đơn đã mua sản phẩm đó đã mua sản phẩm đó cùng số lượng mua (nếu có).

SELECT SP.MaSP, TenSP, DonGia, MaHD, SoLuong
FROM SANPHAM SP
LEFT OUTER JOIN CHITIETHD CT ON CT.MaSP = SP.MaSP