Skip to content
SQL errors / Fix “Column Count Doesn't Match Value Count” in SQL
SQL error

Fix “Column Count Doesn't Match Value Count” in SQL

An INSERT supplies a different number of values than the columns it fills. Name the columns, then give one value for each.

The exact message
DuckDB
Binder Error: table restock_list has 4 columns but 3 values were supplied

With a column list: Column name/value mismatch for insert on restock_list: expected 2 columns but 3 values were supplied.

MySQL
Column count doesn't match value count at row 1

Error 1136.

PostgreSQL
INSERT has more expressions than target columns

Only for too many values. Too few, with no column list, fill the first columns and leave the rest to their defaults, without an error. With a list: INSERT has more target columns than expressions.

SQL Server
Column name or number of supplied values does not match table definition.

Msg 213. With a column list, Msg 109 or 110: There are more (or fewer) columns in the INSERT statement than values specified in the VALUES clause.

Oracle
ORA-00947: not enough values

Too many values is ORA-00913: too many values.

SQLite
table restock_list has 4 columns but 3 values were supplied

With a column list: 3 values for 2 columns. Checked on SQLite 3.53.

The symptom

An INSERT fails before it adds a row. MySQL says the column count doesn't match the value count at row 1, PostgreSQL says the INSERT has more expressions than target columns, and DuckDB says the table has 4 columns but 3 values were supplied.

Without a column list, an INSERT fills every column, in the order the table defines them, so it needs one value for each. The table below has four columns, and the INSERT leaves out status, expecting its default to fill it:

The fix: name the columns you fill

The query that fails
create or replace table restock_list (
  product_id   integer,
  product_name varchar,
  units        integer,
  status       varchar default 'draft'
);
insert into restock_list values (4, 'Pothos', 16);

Running it raises has 4 columns but 3 values were supplied.

The corrected query
create or replace table restock_list (
  product_id   integer,
  product_name varchar,
  units        integer,
  status       varchar default 'draft'
);
insert into restock_list (product_id, product_name, units)
values (4, 'Pothos', 16);
select * from restock_list;

Open the corrected query in the playground

With a column list, the values only have to match the list. status is left out, so it gets its default, 'draft'. The list also protects the INSERT from later changes: when someone adds a column to the table, an INSERT without a list starts failing with this error, and one with a list keeps working.

To fill every column but let one take its default, keep all the values and write default in that position:

Right: DEFAULT in the values
create or replace table restock_list (
  product_id   integer,
  product_name varchar,
  units        integer,
  status       varchar default 'draft'
);
insert into restock_list values (4, 'Pothos', 16, default);
insert into restock_list values (7, 'Tomato Seeds', 75, default);
select * from restock_list order by product_id;

A list and values that disagree

With a column list, the count has to match the list instead. DuckDB words that case differently:

Wrong: two columns, three values
insert into restock_list (product_id, product_name)
values (11, 'Hand Cultivator', 17);

It fails with Column name/value mismatch for insert on restock_list: expected 2 columns but 3 values were supplied. Either add units to the list or drop the 17.

INSERT from a SELECT

The rule is the same when the rows come from a query: the SELECT must return one column per target column, in the same order. Column names don't matter, only positions:

Right: three columns listed, three selected
insert into restock_list (product_id, product_name, units)
select product_id,
       product_name,
       reorder_level * 2 - quantity_on_hand
from products
where quantity_on_hand <= reorder_level
  and not discontinued
  and product_id not in (4, 7);
select * from restock_list order by product_id;

DuckDB can match by name instead: insert into restock_list by name select ... fills each column from the SELECT column with the same name and leaves the rest to their defaults. Databricks has the same option; PostgreSQL, MySQL, and SQL Server don't.

PostgreSQL fills in quietly

PostgreSQL only raises its error for too many values. With too few and no column list, it fills the first columns in order and leaves the rest to their defaults, so a value can land in the wrong column without an error. Name the columns there too.

How other engines word it

Engine Message
DuckDB Binder Error: table restock_list has 4 columns but 3 values were supplied With a column list: Column name/value mismatch for insert on restock_list: expected 2 columns but 3 values were supplied.
MySQL Column count doesn't match value count at row 1 Error 1136.
PostgreSQL INSERT has more expressions than target columns Only for too many values. Too few, with no column list, fill the first columns and leave the rest to their defaults, without an error. With a list: INSERT has more target columns than expressions.
SQL Server Column name or number of supplied values does not match table definition. Msg 213. With a column list, Msg 109 or 110: There are more (or fewer) columns in the INSERT statement than values specified in the VALUES clause.
Oracle ORA-00947: not enough values Too many values is ORA-00913: too many values.
SQLite table restock_list has 4 columns but 3 values were supplied With a column list: 3 values for 2 columns. Checked on SQLite 3.53.

Related errors

Learn more