Background
A colleague encountered a perplexing MySQL issue: querying WHERE a = 0
on a VARCHAR
column returned rows containing Chinese characters, despite no literal "0"
values. This article reproduces the problem across MySQL, Oracle, and SQL Server to highlight MySQL’s unique handling of implicit conversions.
Problem Analysis
1. Test Setup
- Tables: Created identical schemas in MySQL, Oracle, and SQL Server with
VARCHAR
fields. - Data: Inserted mixed values (
'testa'
,NULL
,'test'
).
2. Execution Results
- MySQL: Returned all non-
NULL
VARCHAR
rows (e.g.,"testa"
), triggering a warning:
SELECT * FROM test WHERE a = 0;
-- Warning: Truncated incorrect DOUBLE value: 'testa'
- Oracle/SQL Server: Rejected the query with explicit errors:
- Oracle:
ORA-01722: invalid number
- SQL Server:
Error converting data type varchar to int
- Oracle:
3 Root Cause
MySQL implicitly converts VARCHAR
to numeric types by truncating non-numeric prefixes. For example:
SELECT 0 = "testa"; -- Evaluates to 0 = "" (TRUE)
This behavior deviates from Oracle/SQL Server, which prioritize type safety over silent coercion.
Solutions
1. Enforce Type Consistency
Ensure operands match in type:
-- Use quoted literals for VARCHAR comparisons
SELECT * FROM test WHERE a = '0';
2. Avoid Implicit Conversions
Explicitly cast values when necessary:
SELECT * FROM test WHERE CAST(a AS INTEGER) = 0;
3. Disable Strict Mode (Not Recommended)
While enabling strict mode (sql_mode = STRICT_TRANS_TABLES
) prevents invalid conversions, it may disrupt legacy applications.
Key Takeaways
- Type Safety Matters: Prefer
VARCHAR = 'string'
overVARCHAR = numeric
to avoid silent failures. - Cross-Database Parity: MySQL’s lenient conversions differ from Oracle/SQL Server, risking data inconsistencies.
- Monitor Warnings: Enable
SHOW WARNINGS
during development to catch truncation issues early.