Bạn đã thành thạo T-SQL và PostgreSQL. File này đối chiếu từng khái niệm để bạn học Python nhanh hơn — và cảnh báo những chỗ hai ngôn ngữ khác nhau đủ để gây lỗi.
Bạn đã thành thạo T-SQL và PostgreSQL. File này đối chiếu từng khái niệm để bạn học Python nhanh hơn — và cảnh báo những chỗ hai ngôn ngữ khác nhau đủ để gây lỗi.
1. Khác biệt nền tảng
SQL
Python
Loại ngôn ngữ
Declarative (khai báo)
Imperative (mệnh lệnh)
Bạn viết gì
Mô tả kết quả muốn có
Mô tả từng bước thực hiện
Ai quyết định cách làm
Query optimizer
Chính bạn
Phạm vi
Chỉ dữ liệu trong database
Mọi thứ: file, mạng, giao diện, tính toán
Tối ưu hóa
DBMS lo
Bạn phải tự lo
2. Bảng đối chiếu cú pháp cơ bản
Khái niệm
T-SQL
Python
Ghi chú
Kết thúc lệnh
;
Xuống dòng
Python không cần ;
Khối lệnh
BEGIN ... END
Thụt lề 4 space
⚠️ Khác biệt lớn nhất
Phân biệt hoa/thường
Không (từ khóa)
Có, tuyệt đối
⚠️ Nguồn lỗi phổ biến
Khai báo biến
DECLARE @x INT
x = 0
Không cần khai báo kiểu
Gán giá trị
SET @x = 5
x = 5
So sánh bằng
=
==
⚠️ Dễ nhầm
Khác
<> hoặc !=
!=
Nối chuỗi
+ hoặc CONCAT()
+ hoặc f-string
Comment 1 dòng
--
#
Comment nhiều dòng
/* ... */
Nhiều dòng #
Python không có block comment
Chỉ số chuỗi
Bắt đầu từ 1
Bắt đầu từ 0
⚠️ Lỗi off-by-one
Toán tử AND/OR
AND, OR, NOT
and, or, not
Python viết thường
3. Kiểu dữ liệu
SQL Server
PostgreSQL
Python
Cảnh báo
INT, BIGINT
integer, bigint
int
Python không giới hạn độ lớn
DECIMAL(18,2), MONEY
numeric
Decimal
⚠️ Dùng cho tiền, không dùng float
FLOAT, REAL
real, double precision
float
Có sai số ở cả 2 bên
VARCHAR, NVARCHAR
varchar, text
str
Python 3 mặc định Unicode
CHAR
char
str
Python không có kiểu độ dài cố định
BIT
boolean
bool
True/False viết hoa chữ đầu
DATE
date
datetime.date
DATETIME2
timestamp
datetime.datetime
TIME
time
datetime.time
NULL
NULL
None
⚠️ Hành vi khác nhau, xem mục 4
VARBINARY
bytea
bytes
—
json, jsonb
dict (qua module json)
—
array
list
Cảnh báo về tiền tệ
# ❌ SAI cho phần mềm kế toántong = 0.1 + 0.2print(tong) # 0.30000000000000004# ✅ ĐÚNGfrom decimal import Decimaltong = Decimal("0.1") + Decimal("0.2")print(tong) # 0.3
Đây là lý do bạn dùng DECIMAL(18,2) chứ không dùng FLOAT trong SQL Server. Nguyên tắc hoàn toàn giống nhau ở Python.
SQL cho NULL lan truyền âm thầm → dễ ra kết quả sai mà không biết.
Python báo lỗi ngay → dễ phát hiện, nhưng chương trình dừng.
Khi lấy dữ liệu từ database về Python, luôn xử lý None trước khi tính toán:
tong = sum(kh["cong_no"] or 0 for kh in danh_sach)
COALESCE tương đương
SELECT COALESCE(Email, N'chua co') FROM KhachHang
email = kh.get("email") or "chua co" # Cẩn thận: 0 và "" cũng bị thayemail = kh.get("email", "chua co") # Chỉ thay khi khóa không tồn tạiemail = kh["email"] if kh["email"] is not None else "chua co" # Chính xác nhất
[{"ma": kh["ma"], "ten": kh["ten"]} for kh in khach_hang]# Hoặc chỉ lấy 1 cột[kh["ten"] for kh in khach_hang]
6.3. WHERE
SELECT * FROM KhachHang WHERE CongNo > 0;SELECT * FROM KhachHang WHERE Tinh = 'Hue' AND CongNo > 1000000;SELECT * FROM KhachHang WHERE Tinh IN ('Hue', 'HCM');SELECT * FROM KhachHang WHERE CongNo BETWEEN 1000000 AND 50000000;SELECT * FROM KhachHang WHERE TenKH LIKE N'Nguyen%';SELECT * FROM KhachHang WHERE TenKH LIKE N'%Van%';
[kh for kh in khach_hang if kh["no"] > 0][kh for kh in khach_hang if kh["tinh"] == "Hue" and kh["no"] > 1_000_000][kh for kh in khach_hang if kh["tinh"] in ("Hue", "HCM")][kh for kh in khach_hang if 1_000_000 <= kh["no"] <= 50_000_000][kh for kh in khach_hang if kh["ten"].startswith("Nguyen")][kh for kh in khach_hang if "Van" in kh["ten"]]
6.4. ORDER BY
SELECT * FROM KhachHang ORDER BY CongNo DESC;SELECT * FROM KhachHang ORDER BY Tinh, TenKH;
no = [kh["no"] for kh in khach_hang]print(len(khach_hang)) # COUNT(*)print(sum(no)) # SUMprint(sum(no) / len(no)) # AVGprint(min(no)) # MINprint(max(no)) # MAX
SELECT COUNT(*) FROM KhachHang WHERE CongNo > 0;
len([kh for kh in khach_hang if kh["no"] > 0])# hoặcsum(1 for kh in khach_hang if kh["no"] > 0)
6.7. GROUP BY
SELECT Tinh, COUNT(*) AS SoLuong, SUM(CongNo) AS TongNoFROM KhachHangGROUP BY TinhORDER BY TongNo DESC;
from collections import defaultdictnhom = defaultdict(lambda: {"so_luong": 0, "tong_no": 0})for kh in khach_hang: nhom[kh["tinh"]]["so_luong"] += 1 nhom[kh["tinh"]]["tong_no"] += kh["no"]for tinh, tt in sorted(nhom.items(), key=lambda x: x[1]["tong_no"], reverse=True): print(f"{tinh:<8}{tt['so_luong']:>5}{tt['tong_no']:>18,}")
6.8. GROUP BY … HAVING
SELECT Tinh, SUM(CongNo) AS TongNoFROM KhachHangGROUP BY TinhHAVING SUM(CongNo) > 10000000;
ket_qua = {t: tt for t, tt in nhom.items() if tt["tong_no"] > 10_000_000}
6.9. DISTINCT
SELECT DISTINCT Tinh FROM KhachHang;
set(kh["tinh"] for kh in khach_hang) # Mất thứ tựlist(dict.fromkeys(kh["tinh"] for kh in khach_hang)) # Giữ thứ tự
6.10. CASE WHEN
SELECT MaKH, CASE WHEN CongNo = 0 THEN N'Khong no' WHEN CongNo < 10000000 THEN N'No it' ELSE N'No nhieu' END AS PhanLoaiFROM KhachHang;
def phan_loai(no): if no == 0: return "Khong no" elif no < 10_000_000: return "No it" else: return "No nhieu"[{"ma": kh["ma"], "phan_loai": phan_loai(kh["no"])} for kh in khach_hang]
hoa_don = [ {"so_hd": "HD001", "ma_kh": "KH001", "so_tien": 15_000_000}, {"so_hd": "HD002", "ma_kh": "KH002", "so_tien": 8_500_000}, {"so_hd": "HD003", "ma_kh": "KH999", "so_tien": 3_000_000}, # KH không tồn tại]# Tạo index để tra cứu nhanh (tương đương index trong DB)index_kh = {kh["ma"]: kh for kh in khach_hang}# INNER JOIN — chỉ lấy dòng khớpinner = [ {"so_hd": hd["so_hd"], "ten_kh": index_kh[hd["ma_kh"]]["ten"], "so_tien": hd["so_tien"]} for hd in hoa_don if hd["ma_kh"] in index_kh]# LEFT JOIN — lấy hết bên trái, bên phải None nếu không khớpleft = [ { "so_hd": hd["so_hd"], "ten_kh": index_kh.get(hd["ma_kh"], {}).get("ten"), "so_tien": hd["so_tien"], } for hd in hoa_don]
6.12. UNION / INTERSECT / EXCEPT
SELECT MaKH FROM BangAUNIONSELECT MaKH FROM BangB;
a = {"KH001", "KH002", "KH003"}b = {"KH002", "KH003", "KH004"}a | b # UNION -> {KH001, KH002, KH003, KH004}a & b # INTERSECT -> {KH002, KH003}a - b # EXCEPT -> {KH001}a ^ b # FULL OUTER trừ phần chung -> {KH001, KH004}
BEGIN TRANSACTION;BEGIN TRY UPDATE TaiKhoan SET SoDu = SoDu - 1000 WHERE Id = 1; UPDATE TaiKhoan SET SoDu = SoDu + 1000 WHERE Id = 2; COMMIT;END TRYBEGIN CATCH ROLLBACK;END CATCH
try: cur.execute("UPDATE TaiKhoan SET SoDu = SoDu - ? WHERE Id = ?", (1000, 1)) cur.execute("UPDATE TaiKhoan SET SoDu = SoDu + ? WHERE Id = ?", (1000, 2)) conn.commit()except Exception: conn.rollback() raise
Làm càng nhiều càng tốt trong SQL, chỉ mang về Python những gì SQL không làm được.
Việc
Nên làm ở
Lọc, nhóm, tổng hợp dữ liệu lớn
SQL — có index, optimizer
JOIN nhiều bảng
SQL
Sắp xếp, phân trang
SQL
Đọc/ghi file Excel, CSV
Python
Gọi API bên ngoài
Python
Gửi email, tạo file PDF
Python
Logic nghiệp vụ phức tạp nhiều nhánh
Python
Vẽ biểu đồ, báo cáo trực quan
Python
Tự động hóa lặp lại theo lịch
Python
Ví dụ sai và đúng
# ❌ SAI — mang 1 triệu dòng về rồi mới lọc bằng Pythoncur.execute("SELECT * FROM HoaDon")tat_ca = cur.fetchall()loc = [hd for hd in tat_ca if hd["Nam"] == 2026]# ✅ ĐÚNG — để SQL lọc, chỉ mang về cái cầncur.execute("SELECT * FROM HoaDon WHERE YEAR(NgayLap) = ?", (2026,))loc = cur.fetchall()