Sửa lỗi MySQL ERROR 1292: Truncated incorrect DOUBLE value khi UPDATE

intermediate🗄️ MySQL2026-05-21| MySQL 5.7+, MySQL 8.0+, MariaDB 10.x — mọi hệ điều hành (Linux, macOS, Windows), mọi client (mysql CLI, DBeaver, phpMyAdmin, ORM ứng dụng)

Error Message

ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'some_string_value'
#mysql#update#kiểu-dữ-liệu#sql-error

Lỗi xuất hiện giữa chừng khi UPDATE

Bạn chạy một câu UPDATE tưởng như bình thường. MySQL trả về:

ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'active'

Cột tồn tại. Cú pháp đúng. Không có gì rõ ràng sai. Vấn đề là: MySQL đang cố ép kiểu một chuỗi sang DOUBLE ở đâu đó trong câu query. Với strict mode được bật, MySQL từ chối nuốt trôi giá trị sai và báo lỗi thay vì xử lý ngầm.

Nguyên nhân

Lỗi 1292 xảy ra khi MySQL cố chuyển đổi một chuỗi sang kiểu số — INT, DOUBLE, FLOAT, hoặc DECIMAL — mà chuỗi đó không phải là số hợp lệ. Trong MySQL 5.6 trở về trước, điều này sẽ bị cắt ngầm về 0. Từ MySQL 5.7 trở đi, STRICT_TRANS_TABLES được bật mặc định. Nghĩa là việc cắt cụt trở thành lỗi, không còn là sự hỏng dữ liệu âm thầm nữa.

Điều khiến nhiều người bối rối: giá trị gây lỗi thường nằm trong mệnh đề WHERE, không phải mệnh đề SET.

Debug: tìm ra thủ phạm thực sự

Bước 1 — Kiểm tra sql_mode hiện tại

SELECT @@sql_mode;

Thấy STRICT_TRANS_TABLES hoặc STRICT_ALL_TABLES trong kết quả? Đó là lý do MySQL báo lỗi thay vì tự động chuyển đổi. Đừng tắt nó — hãy sửa câu query.

Bước 2 — Xác định kiểu dữ liệu các cột liên quan

DESCRIBE your_table;
-- hoặc
SHOW COLUMNS FROM your_table;

Kiểm tra tất cả các cột được tham chiếu trong câu UPDATE — cả SET lẫn WHERE. Bất kỳ cột nào có kiểu INT, DOUBLE, FLOAT, hoặc DECIMAL mà đang được so sánh hoặc gán giá trị chuỗi đều là nghi phạm.

Bước 3 — Cô lập mệnh đề gây lỗi

Mệnh đề WHERE phức tạp? Hãy chạy thử dưới dạng SELECT trước:

SELECT * FROM orders
WHERE status = 'active'
  AND category_id = 'electronics';

Nếu category_id là cột INT, câu SELECT này sẽ ném ra lỗi 1292 tương tự. Bạn đã tìm ra thủ phạm.

Các tình huống thường gặp và cách sửa

Tình huống 1: Giá trị chuỗi trong WHERE trên cột số

Chín trên mười trường hợp là do đây. Một khóa ngoại hoặc mã trạng thái kiểu số bị lọc bằng một chuỗi ký tự.

-- Sai: category_id là INT nhưng bạn truyền vào chuỗi
UPDATE products
SET price = price * 0.9
WHERE category_id = 'electronics';

-- Đúng: dùng ID số nguyên thực sự
UPDATE products
SET price = price * 0.9
WHERE category_id = 5;

Tình huống 2: Gán chuỗi cho cột số trong SET

-- Sai: stock là INT
UPDATE inventory
SET stock = 'none'
WHERE product_id = 42;

-- Đúng: dùng 0 hoặc NULL thay thế
UPDATE inventory
SET stock = 0
WHERE product_id = 42;

-- Hoặc nếu cột cần lưu văn bản, đổi kiểu dữ liệu
ALTER TABLE inventory MODIFY stock VARCHAR(20);

Tình huống 3: Dùng sai toán tử logic (&&, ||)

Các toán tử &&|| của MySQL ép cả hai vế sang DOUBLE. Truyền một toán hạng chuỗi vào là lỗi 1292 nổ ra ngay.

-- Sai: MySQL cố ép 'active' sang DOUBLE
UPDATE orders
SET processed = 1
WHERE is_paid = 1 && status = 'active';

-- Đúng: dùng AND thay vì &&
UPDATE orders
SET processed = 1
WHERE is_paid = 1 AND status = 'active';

Tình huống 4: Chuỗi đến từ ứng dụng hoặc ORM

Câu query trông ổn khi nhìn riêng lẻ. Vấn đề là một tham số được bind lúc runtime — hãy kiểm tra chỗ ứng dụng thực sự tạo ra giá trị đó.

-- Ví dụ Python SQLAlchemy bị lỗi
db.execute(
    "UPDATE users SET role_id = :role WHERE id = :id",
    {"role": "admin", "id": user_id}  # role_id là INT, không phải VARCHAR
)

-- Đúng: truyền đúng kiểu dữ liệu
db.execute(
    "UPDATE users SET role_id = :role WHERE id = :id",
    {"role": 3, "id": user_id}  # ID số nguyên của role 'admin'
)

Tình huống 5: Phép tính trên các cột kiểu hỗn hợp

-- Sai: discount là VARCHAR('10%'), MySQL cố nhân với một chuỗi
UPDATE orders
SET final_price = base_price * (1 - discount)
WHERE id = 101;

-- Đúng: bỏ '%' và ép kiểu tường minh
UPDATE orders
SET final_price = base_price * (1 - CAST(REPLACE(discount, '%', '') AS DECIMAL(5,2)) / 100)
WHERE id = 101;

Giải pháp tạm thời khi cần chạy gấp

Chỉ dùng cách này khi bạn biết rõ dữ liệu nào đang được chuyển đổi và bạn sẽ dọn dẹp ngay sau đó.

-- Tắt strict mode chỉ trong session này
SET SESSION sql_mode = REPLACE(@@SESSION.sql_mode, 'STRICT_TRANS_TABLES', '');

-- Chạy câu UPDATE của bạn
UPDATE ...

-- Khôi phục strict mode
SET SESSION sql_mode = @@GLOBAL.sql_mode;

Khi không có strict mode, MySQL âm thầm cắt các chuyển đổi sai về 0. Nghĩa là price = '10abc' lặng lẽ thành price = 10, và status_code = 'active' thành status_code = 0. Hãy kiểm tra các dòng bị ảnh hưởng ngay khi câu UPDATE hoàn tất.

Xác nhận cách sửa đã hoạt động

-- 1. Chạy câu UPDATE không còn lỗi
UPDATE orders SET processed = 1 WHERE is_paid = 1 AND status = 'active';
-- Query OK, N rows affected (0.01 sec)

-- 2. Xác nhận dữ liệu đã thay đổi đúng
SELECT id, processed, status FROM orders
WHERE is_paid = 1 AND status = 'active'
LIMIT 10;

-- 3. Kiểm tra không có dòng nào bị về 0 ngoài ý muốn
SELECT COUNT(*) FROM orders WHERE processed = 0 AND is_paid = 1 AND status = 'active';
-- Kết quả phải là 0

Lâu dài: ngăn lỗi tái diễn

  • Giữ strict mode luôn bật. Nó phát hiện sự không khớp kiểu trước khi dữ liệu bị hỏng âm thầm. Chạy không có strict mode trên production là cách bạn kết thúc với price = 0 trên hàng nghìn dòng mà không có gì trong error log.
  • Khớp kiểu dữ liệu ngay từ tầng ứng dụng. Nếu cột là INT, luôn bind số nguyên — đừng dựa vào MySQL tự ép kiểu để che đi sự khác biệt.
  • Test các mệnh đề WHERE phức tạp dưới dạng SELECT trước trước khi chạy UPDATE trên bảng production.
  • Trong ORM, kiểm tra kỹ ánh xạ cột. Một trường chuỗi trên model được ánh xạ tới cột INT trong DB sẽ qua được kiểm tra kiểu ở tầng ứng dụng, rồi thầm lặng bị lỗi ở tầng DB.
  • Dùng CAST() tường minh khi kết hợp các kiểu khác nhau trong biểu thức — điều này làm cho việc chuyển đổi rõ ràng và có chủ đích, đồng thời dễ hiểu hơn cho người đọc query sau này.

Related Error Notes