Construct an inline table from literal values without referencing a persistent table. Useful for multi-row inserts, testing, and constructing ad-hoc result sets to join against.

Generates a derived table of literal values, useful for defining small lookup tables on the fly without creating a temporary table. SELECT * FROM (VALUES (1, a), (2, b)) AS t(id, name) is portable and useful in INSERT and JOIN contexts.

Compatibility

Filter by Database
SQL VALUES CLAUSE Compatibility Across Databases
Database System Support Status Since Version Notes
MySQL Native 8.0.19 Multi-row INSERT VALUES has been supported since early MySQL versions. The TABLE and VALUES statement as a standalone query (VALUES ROW(...), ROW(...)) was added in MySQL 8.0.19, providing an inline table construct. Prior to 8.0.19, use UNION ALL of SELECT literals to simulate an inline table.
PostgreSQL Native 8.2 VALUES is a full first-class relation since PostgreSQL 8.2 — it can appear anywhere a table or subquery can: in FROM, CTE, UNION, INSERT, etc. Column names in the alias are required when the VALUES clause is used as a subquery or CTE. Row type is inferred from the first row; explicit casts may be needed for ambiguous literals.
SQL Server Native 2008 VALUES as an inline table constructor available since SQL Server 2008. Syntax requires an alias with column names. Often used for multi-row inserts and lookup tables in CTEs. Cannot exceed 1000 rows in a single VALUES constructor.
Oracle Not Supported - Oracle does not support a VALUES clause as a standalone table constructor in SELECT queries. Multi-row INSERT is supported via INSERT ALL or INSERT with a SELECT from DUAL for a single row. For an inline lookup table, use a UNION ALL SELECT from DUAL, or a collection type with TABLE().
SQLite Native 3.8.3 VALUES as a table-value constructor in SELECT/FROM supported since SQLite 3.8.3. Supports alias with column names. Fully usable in CTEs, FROM clauses, and UNION.

Details

Multi-row INSERT VALUES (syntax: INSERT INTO t VALUES (r1), (r2), ...) is broadly supported across all engines. The more interesting case is VALUES as a standalone table constructor usable in SELECT, FROM, CTEs, and JOINs — this works in PostgreSQL (8.2+), SQL Server (2008+), SQLite (3.8.3+), and MySQL (8.0.19+ with ROW() wrapper). Oracle is the outlier: it has no VALUES table constructor and requires UNION ALL of SELECT ... FROM DUAL as the workaround. The MySQL VALUES ROW() syntax differs from all other engines — other engines use plain VALUES (row), (row) without the ROW() keyword.

Standard Syntax

-- Inline table of literal values: SELECT * FROM (VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Carol')) AS t(id, name); -- Multi-row INSERT: INSERT INTO colors (id, name) VALUES (1, 'red'), (2, 'green'), (3, 'blue');

Version Support

MySQL: Native since 8.0.19 PostgreSQL: Native since 8.2 SQL Server: Native since 2008 Oracle: Not supported SQLite: Native since 3.8.3

Per-Database Syntax & Notes

MySQL Native syntax

Multi-row INSERT VALUES has been supported since early MySQL versions. The TABLE and VALUES statement as a standalone query (VALUES ROW(...), ROW(...)) was added in MySQL 8.0.19, providing an inline table construct. Prior to 8.0.19, use UNION ALL of SELECT literals to simulate an inline table.

-- Multi-row INSERT (supported since early versions): INSERT INTO colors (id, name) VALUES (1, 'red'), (2, 'green'), (3, 'blue'); -- Standalone VALUES statement (8.0.19+): VALUES ROW(1, 'Alice'), ROW(2, 'Bob'); -- Inline table via derived query (pre-8.0.19 workaround): SELECT * FROM ( SELECT 1 AS id, 'Alice' AS name UNION ALL SELECT 2, 'Bob' UNION ALL SELECT 3, 'Carol' ) AS t; -- JOIN against inline values: SELECT p.*, v.label FROM products p JOIN (VALUES ROW(1,'small'), ROW(2,'medium'), ROW(3,'large')) AS v(id,label) ON p.size_id = v.id;

PostgreSQL Native syntax

VALUES is a full first-class relation since PostgreSQL 8.2 — it can appear anywhere a table or subquery can: in FROM, CTE, UNION, INSERT, etc. Column names in the alias are required when the VALUES clause is used as a subquery or CTE. Row type is inferred from the first row; explicit casts may be needed for ambiguous literals.

-- Inline table: SELECT * FROM (VALUES (1, 'Alice'), (2, 'Bob')) AS t(id, name); -- CTE using VALUES: WITH priority_map(level, label) AS ( VALUES (1, 'low'), (2, 'medium'), (3, 'high') ) SELECT o.id, pm.label FROM orders o JOIN priority_map pm ON pm.level = o.priority; -- UNION with VALUES: SELECT id, name FROM customers UNION ALL VALUES (0, 'Anonymous'); -- Multi-row INSERT: INSERT INTO colors (id, name) VALUES (1, 'red'), (2, 'green'), (3, 'blue');

SQL Server Native syntax

VALUES as an inline table constructor available since SQL Server 2008. Syntax requires an alias with column names. Often used for multi-row inserts and lookup tables in CTEs. Cannot exceed 1000 rows in a single VALUES constructor.

-- Inline table: SELECT * FROM (VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Carol')) AS t(id, name); -- JOIN against inline values: SELECT p.*, v.label FROM products p JOIN (VALUES (1,'S'),(2,'M'),(3,'L')) AS v(size_id, label) ON p.size_id = v.size_id; -- CTE with VALUES: WITH codes(code, description) AS ( VALUES ('A','Active'),('I','Inactive'),('P','Pending') ) SELECT u.name, c.description FROM users u JOIN codes c ON u.status = c.code; -- Multi-row INSERT: INSERT INTO colors (id, name) VALUES (1,'red'),(2,'green'),(3,'blue');

Oracle Alternative syntax

Oracle does not support a VALUES clause as a standalone table constructor in SELECT queries. Multi-row INSERT is supported via INSERT ALL or INSERT with a SELECT from DUAL for a single row. For an inline lookup table, use a UNION ALL SELECT from DUAL, or a collection type with TABLE().

-- Single-row INSERT (Oracle standard): INSERT INTO colors (id, name) VALUES (1, 'red'); -- Multi-row INSERT via INSERT ALL: INSERT ALL INTO colors (id, name) VALUES (1, 'red') INTO colors (id, name) VALUES (2, 'green') INTO colors (id, name) VALUES (3, 'blue') SELECT 1 FROM DUAL; -- Inline table workaround (UNION ALL from DUAL): SELECT * FROM ( SELECT 1 AS id, 'Alice' AS name FROM DUAL UNION ALL SELECT 2, 'Bob' FROM DUAL UNION ALL SELECT 3, 'Carol' FROM DUAL ) t;

SQLite Native syntax

VALUES as a table-value constructor in SELECT/FROM supported since SQLite 3.8.3. Supports alias with column names. Fully usable in CTEs, FROM clauses, and UNION.

-- Inline table: SELECT * FROM (VALUES (1, 'Alice'), (2, 'Bob')) AS t(id, name); -- CTE with VALUES: WITH priority(level, label) AS ( VALUES (1,'low'),(2,'medium'),(3,'high') ) SELECT * FROM priority; -- Multi-row INSERT: INSERT INTO colors (id, name) VALUES (1,'red'),(2,'green'),(3,'blue');