mysql 8.0.19+ 支持标准 sql 的 values 表达式,需用 row() 构造行、括号包裹、as 指定别名及列名,如 select * from (values row(1,'a'), row(2,'b')) as t(id,name);8.0.19 之前不支持,须用 union all 替代。

VALUES() 在 MySQL 8.0 中不是通用的 VALUES 表达式
MySQL 8.0 并不支持像 PostgreSQL 那样直接用 VALUES (1,'a'),(2,'b') 构造临时表。你写的 VALUES() 会被解析为函数调用,而 MySQL 没有这个内置函数——执行会报错 ERROR 1305 (42000): FUNCTION test.VALUES does not exist。
真正能“模拟 VALUES 表达式”效果的是 VALUES ROW(),但它只在特定上下文中合法:必须作为 INSERT ... VALUES ROW(...) 的一部分,或配合 SELECT ... FROM (VALUES ...) AS t 语法(该语法在 MySQL 8.0.19+ 才正式支持)。
- MySQL 8.0.19 之前:无法直接写
(VALUES ROW(1,'a'), ROW(2,'b')) AS t - MySQL 8.0.19 及之后:支持标准 SQL 的
VALUES表达式作为派生表 - 即使支持,也要求显式指定列别名,否则会报
ERROR 1248 (42000): Every derived table must have its own alias
MySQL 8.0.19+ 正确写法:用 VALUES 构造派生表
确认你的 MySQL 版本 ≥ 8.0.19 后,可以这样构造一行或多行临时数据:
SELECT * FROM (VALUES ROW(1, 'Alice'), ROW(2, 'Bob'), ROW(3, 'Charlie')) AS t(id, name);
注意几个硬性要求:
-
VALUES必须包裹在括号里,且后面紧跟AS t(...)别名和列名 - 每行必须用
ROW()包裹,不能省略(VALUES (1,'a')会报语法错误) - 列名列表
(id, name)不可省略;否则 MySQL 无法推断字段类型和名称 - 所有
ROW()中的值数量、类型需一致,否则触发类型转换或报错
兼容旧版本(如 8.0.18 或更低)的替代方案
如果不能升级,就只能绕过 VALUES,改用 UNION ALL 模拟:
SELECT 1 AS id, 'Alice' AS name UNION ALL SELECT 2, 'Bob' UNION ALL SELECT 3, 'Charlie';
这种写法在所有 MySQL 5.7+ 都可用,但要注意:
- 每列的表达式类型要尽量一致,避免隐式转换导致排序/比较异常
-
UNION ALL比VALUES多一层执行计划开销,大数据量时性能略差 - 不能直接用于
INSERT INTO ... SELECT的右侧而不加括号包裹(MySQL 要求派生表必须有别名) - 若用于子查询,需套一层
(...)并加AS t,例如:INSERT INTO users SELECT * FROM (SELECT 1,'x' UNION ALL SELECT 2,'y') AS t(a,b)
VALUES() 常见误用与调试建议
看到有人写 SELECT VALUES(1,2) 或 FROM VALUES(...) 报错,基本都是混淆了语法层级。关键点在于:
-
VALUES()仅在INSERT ... VALUES (...)中表示“插入值”,此时它是语句关键词,不是函数也不是表达式 - 在
SELECT或FROM子句中单独出现VALUES,必须符合标准 SQL 的VALUES row_constructor形式,且依赖版本 - 使用前务必检查:
SELECT VERSION();,并确认是否启用了标准 SQL 模式(sql_mode中不含STRICT_TRANS_TABLES等可能影响隐式转换的选项) - 测试时优先用最小复现:
SELECT * FROM (VALUES ROW(1)) AS t(x);,再逐步扩展
最易被忽略的是 ROW() 的强制性和列别名的不可省略性——少一个括号或漏写 AS t(col) 就直接语法错误,没有模糊容错。











