isnumeric常误判,因其判断标准是“能否转为任意数字类型”,而非“是否为纯数字字符串”,故‘1e4’、‘$123’、‘,’等均返回1;推荐用try_cast替代或结合patindex做精确匹配。

ISNUMERIC在SQL Server中为什么经常误判
ISNUMERIC() 看起来是判断数字的“标准答案”,但它实际返回 1 的情况远超预期:比如 '.'、'+' 、'-' 、'1e4'、甚至 CHAR(9)(制表符)都会被识别为“可转数字”。这不是 bug,而是设计如此——它只表示“能被某种数字类型隐式转换”,不保证是整数或小数字符串。
实操建议:
- 别用
ISNUMERIC()做业务校验,尤其当字段要转INT或参与数学运算时 - 若必须用,至少加一层过滤:
ISNUMERIC(col) = 1 AND col NOT LIKE '%[^0-9]%' AND col != ''(但仍有缺陷,见下条) - 注意
ISNUMERIC('123 ') = 1(末尾空格也通过),需先RTRIM(LTRIM())
MySQL里用REGEXP匹配纯数字的正确写法
MySQL 8.0+ 支持 REGEXP_LIKE(),5.7 及以前只能用 REGEXP 操作符。关键点在于:必须锚定开头和结尾,否则 'abc123def' 也会匹配成功。
实操建议:
- 匹配非空纯数字(不含正负号、小数点):
col REGEXP '^[0-9]+$' - 允许开头有正负号:
col REGEXP '^[+-]?[0-9]+$' - 允许小数(但要求至少一位数字):
col REGEXP '^[+-]?[0-9]+\.?[0-9]*$'—— 注意这仍会匹配'123.',更严的写法需拆成两部分或用CAST验证 - 空字符串、NULL 需单独处理:
col IS NOT NULL AND col != '' AND col REGEXP '^[0-9]+$'
PostgreSQL和SQLite如何安全判断整数字符串
PostgreSQL 没有内置 ISNUMERIC,但有更可靠的替代方案;SQLite 则连正则都默认不启用,得靠函数兜底。
实操建议:
- PostgreSQL 推荐用异常捕获:
SELECT col FROM t WHERE (col::text ~ '^[0-9]+$') AND (col::integer IS NOT NULL)—— 但注意::integer会在非法值时报错,必须包在DO $$ BEGIN ... EXCEPTION或用TO_NUMBER(col, '999999')(需格式匹配) - 更稳妥的是自定义函数,或直接用
col ~ '^[0-9]+$' AND length(col) (限制位数防溢出) - SQLite 若未编译 ICU,
REGEXP不可用;此时只能用col NOT LIKE '%[^0-9]%' AND col != '' AND col IS NOT NULL,但要注意 SQLite 的LIKE不支持字符类,该写法实际无效 —— 真实可用的是printf('%d', col) IS NOT NULL(仅适用于整数且非空)
跨数据库兼容的最小可行方案
没有一行 SQL 能在所有主流数据库中 100% 正确识别纯数字字符串,但可以退一步:用应用层做最终校验,SQL 层只筛掉明显非法值。
实操建议:
- SQL 层先快速排除:
col IS NOT NULL AND col != '' AND col NOT LIKE '%[^0-9]%' AND col NOT LIKE '% %'(适用于 SQL Server / PostgreSQL / MySQL,但 SQLite 的NOT LIKE '%[^0-9]%'是错的,慎用) - 真正要转数字时,永远在应用代码里 try-catch
parseInt或int(),不要信任任何数据库函数的“数字性”判断 - 如果字段本就应为数字,建表时就用
INT或NUMERIC类型,让约束在入库时生效,比事后校验可靠得多
最常被忽略的一点:业务上所谓“全为数字”,往往隐含位数、范围、是否允许前导零等要求,这些光靠正则或 ISNUMERIC 根本覆盖不到。










