INSERT thêm hàng vào bảng
INSERT là câu lệnh dùng để đưa hàng mới vào bảng. Cấu trúc của nó ngắn và dễ đoán:
Có ba phần cần chú ý:
INSERT INTO books: bảng đích.(title, author, year): các cột mà bạn cung cấp giá trị.VALUES (...): các giá trị, theo đúng thứ tự của danh sách cột.
id không có trong danh sách cột, nên SQLite tự gán giá trị (đây là INTEGER PRIMARY KEY, nên nó nhận rowid). Cột nào bị bỏ qua sẽ lấy giá trị mặc định, hoặc NULL nếu không có mặc định.
Luôn liệt kê tên cột
Bạn có thể bỏ danh sách cột và cung cấp giá trị cho mọi cột theo thứ tự khai báo:
-- Works, but fragile:
INSERT INTO books VALUES (NULL, 'Dune', 'Frank Herbert', 1965);
Đừng làm vậy. Ngay khi ai đó thêm một cột vào books, mọi câu lệnh kiểu này sẽ hỏng hoặc bắt đầu chèn giá trị vào sai cột. Hãy ghi rõ các cột:
Danh sách cột rõ ràng cũng là một dạng tài liệu: câu lệnh tự nó đã dễ đọc, không cần đi tìm định nghĩa bảng.
Thêm nhiều hàng
Bạn có thể thêm nhiều hàng trong một câu lệnh bằng cách liệt kê thêm các bộ giá trị:
Cách này gọn hơn ba câu INSERT riêng lẻ, và SQLite coi toàn bộ là một câu lệnh. Tuy vậy, khi nạp dữ liệu lớn, hiệu năng tăng thật sự là nhờ bọc các lệnh insert trong một transaction, như phần tiếp theo sẽ nói.
Chèn hàng loạt: bọc trong một transaction
Mặc định, mỗi lệnh INSERT là một transaction riêng. SQLite gọi fsync ở cuối mỗi transaction, và chính điều đó làm vòng lặp đơn giản chạy chậm, không phải bản thân các lệnh insert.
Hãy gom chúng lại:
Một lần fsync thay vì năm lần. Với hàng nghìn hàng, chênh lệch có thể lên tới hàng trăm, thậm chí hàng nghìn lần. Nếu có lỗi bên trong, ROLLBACK sẽ hoàn tác toàn bộ lô.
Đây là công thức chuẩn để chèn hàng loạt. Dù bạn gọi SQLite từ Python, Node hay Rust, hãy bọc vòng lặp trong BEGIN / COMMIT.
INSERT ... SELECT: sao chép từ bảng khác
Bạn có thể đổ dữ liệu vào bảng từ một truy vấn thay vì từ giá trị viết sẵn:
Các cột của SELECT được ghép theo vị trí với danh sách cột của INSERT. Tên không cần khớp, thứ tự thì phải khớp. Đây là cách chuẩn để lưu trữ hàng cũ, dựng bảng báo cáo, hoặc sao chép một phần dữ liệu khi migration.
DEFAULT VALUES và các cột bị bỏ qua
Nếu một cột có mệnh đề DEFAULT, bạn có thể bỏ nó khỏi danh sách cột và SQLite sẽ điền giá trị mặc định:
created_at nhận thời điểm hiện tại vì ta không cung cấp giá trị. Nếu muốn một hàng chỉ gồm giá trị mặc định (hữu ích cho hàng giữ chỗ), hãy dùng dạng DEFAULT VALUES:
Hai hàng mới, cả hai đều có value = 0 và id được tự động gán.
INSERT OR IGNORE: bỏ qua hàng trùng
Khi một hàng vi phạm ràng buộc UNIQUE hoặc PRIMARY KEY, hành vi mặc định là hủy câu lệnh và báo lỗi:
Error: UNIQUE constraint failed: users.email
INSERT OR IGNORE đổi hành vi đó thành "lặng lẽ bỏ qua hàng gây lỗi":
Ba hàng được giữ lại. Hàng trùng bị loại mà không báo lỗi. Đây là cách viết quen thuộc trong SQLite để diễn đạt "chỉ thêm nếu chưa có" với dữ liệu mẫu đơn giản: không cần SELECT riêng để kiểm tra trước, không cần xử lý ngoại lệ.
INSERT OR REPLACE: ghi đè hàng trùng
INSERT OR REPLACE xóa hàng xung đột rồi chèn hàng mới vào thay thế:
Cần cẩn thận một điều: REPLACE là DELETE cộng INSERT, không phải UPDATE. Nếu hàng bị xóa có khóa ngoại trỏ tới với ON DELETE CASCADE, các hàng con đó cũng bị xóa theo. Và cột nào không có trong lệnh INSERT mới sẽ trở về giá trị mặc định, chứ không giữ giá trị cũ.
Với hầu hết trường hợp "cập nhật nếu đã có, thêm nếu chưa có", thứ bạn thật sự cần là upsert với ON CONFLICT ... DO UPDATE. Phần đó có trang riêng.
Tóm tắt nhanh
INSERT INTO table (cols) VALUES (...): dạng cơ bản. Luôn liệt kê tên cột.- Thêm nhiều hàng bằng các bộ giá trị cách nhau bởi dấu phẩy sau
VALUES. - Khi nạp dữ liệu lớn thật sự, bọc các lệnh insert trong
BEGIN/COMMIT. INSERT INTO ... SELECT ...sao chép hàng từ một truy vấn.DEFAULT VALUEStạo một hàng chỉ từ giá trị mặc định; các cột bị bỏ qua cũng lấy giá trị mặc định.INSERT OR IGNOREbỏ qua hàng xung đột;INSERT OR REPLACEghi đè chúng (bằng cách xóa rồi chèn).
Tiếp theo: UPDATE
Thêm hàng mới chỉ là một nửa câu chuyện. Nửa còn lại là thay đổi những hàng đã có: tăng một bộ đếm, sửa lỗi chính tả, đánh dấu đơn hàng đã giao. Đó là UPDATE, với những thói quen riêng cần làm đúng (nhất là mệnh đề WHERE). Mời bạn xem ở trang tiếp theo.
Câu hỏi thường gặp
Làm sao để thêm một hàng trong SQLite?
Dùng INSERT INTO table (col1, col2) VALUES (val1, val2);. Liệt kê tên cột là tùy chọn nhưng rất nên làm: câu lệnh vẫn chạy đúng ngay cả khi sau này bảng có thêm cột mới. Nếu không liệt kê cột, bạn phải cung cấp giá trị cho mọi cột theo đúng thứ tự khai báo.
Làm sao để thêm nhiều hàng cùng lúc trong SQLite?
Đặt nhiều bộ giá trị trong ngoặc sau VALUES, cách nhau bằng dấu phẩy: INSERT INTO t (a, b) VALUES (1, 2), (3, 4), (5, 6);. Khi nạp dữ liệu lớn thật sự (hàng nghìn hàng), hãy bọc các lệnh insert trong một transaction duy nhất bằng BEGIN và COMMIT: tốc độ tăng là nhờ điều đó, không phải nhờ cú pháp nhiều hàng.
INSERT OR IGNORE trong SQLite làm gì?
INSERT OR IGNORE bỏ qua những hàng vi phạm ràng buộc UNIQUE, PRIMARY KEY hoặc NOT NULL thay vì báo lỗi. Hàng xung đột bị loại mà không có thông báo, phần còn lại của câu lệnh vẫn tiếp tục. Dùng nó khi bạn muốn 'chỉ thêm nếu chưa có' mà không cần kiểm tra tồn tại riêng.
Vì sao INSERT báo lỗi 'UNIQUE constraint failed'?
SQLite tìm thấy một hàng đã có cùng giá trị trong cột UNIQUE hoặc PRIMARY KEY. Hoặc giá trị đó thật sự bị trùng, hoặc bạn đang chạy lại một script nạp dữ liệu mẫu. Chuyển sang INSERT OR IGNORE để bỏ qua hàng trùng, INSERT OR REPLACE để ghi đè, hoặc dùng ON CONFLICT ... DO UPDATE (upsert) để kiểm soát chi tiết hơn.