Download

The multi-part identifier could not be bound

A name such as c.id or customers.name points at a table that isn’t in scope where you used it. Usually the table has an alias and you wrote its full name, the alias is misspelt, or the table isn’t in the statement’s FROM at all.

SQL Server error 4104· Tested on SQL Server 2022 RTM-CU27 (16.0.4295.3); same messages on 2019 RTM-CU32-GDR and 2025 RTM-CU9· Updated 11 October 2026

The multi-part identifier "customers.name" could not be bound.

What it means

A multi-part identifier is a name with dots in it: c.id, customers.name, dbo.customers.name. SQL Server reads everything before the last dot as a table, or a table’s alias, and looks for it among the tables the statement can see at that point. Error 4104 means there’s no table by that name there, so SQL Server can’t tie (“bind”) the column to anything. It finds this while compiling the batch, so nothing in the batch runs.

Msg 4104, Level 16, State 1, Server 7732422b7f56, Line 1
The multi-part identifier "customers.name" could not be bound.

The table almost always exists. What’s wrong is the name you used for it in that place: once you give a table an alias, the alias is its only name in that query. If the table part is right and the column is wrong (c.nmae), you get error 207 instead.

Common causes

  1. The table’s own name after you gave it an alias. FROM dbo.customers AS c hides the name customers: customers.name and dbo.customers.name both fail, c.name works. This includes ORDER BY customers.name at the end of an aliased query.
  2. A misspelt alias, or one left over from another query: ON o.customer_id = cust.id when the alias is c.
  3. A table that isn’t in the statement at all. Typical in an UPDATE written the way other databases allow: UPDATE orders SET … WHERE customers.name = 'Ada' AND orders.customer_id = customers.id. T-SQL needs customers in a FROM clause.
  4. A table used in an ON before it’s joined. Each ON sees only the tables joined so far, so in … JOIN payments AS p ON p.order_id = o.id JOIN orders AS o ON … the first ON can’t see o.
  5. Comma joins mixed with JOIN. In FROM customers AS c, orders AS o JOIN payments AS p ON p.customer_id = c.id the JOIN binds first, so its ON sees o and p but not c.
  6. A subquery in FROM that refers to the outer query. A derived table can’t see the other tables in the same FROM.

How to fix it

Use the alias everywhere

Give each table a short alias and qualify every column with it, in SELECT, ON, WHERE, GROUP BY and ORDER BY:

SELECT c.name, o.total
FROM dbo.customers AS c
JOIN dbo.orders AS o ON o.customer_id = c.id
ORDER BY c.name;

Qualifying every column also prevents ambiguous column names when two tables share one.

Give UPDATE and DELETE a FROM

T-SQL updates through a join with UPDATE <alias> … FROM, naming the alias of the table you’re changing:

UPDATE o
SET status = 'vip'
FROM dbo.orders AS o
JOIN dbo.customers AS c ON c.id = o.customer_id
WHERE c.name = N'Ada';

DELETE works the same way: DELETE o FROM dbo.orders AS o JOIN dbo.customers AS c ON … WHERE …. When you only need a filter, a subquery avoids the join:

UPDATE dbo.orders
SET status = 'vip'
WHERE customer_id IN (SELECT id FROM dbo.customers WHERE name = N'Ada');

Join in order, and drop comma joins

Write every join as JOIN … ON, and put each condition in the ON of the last table it mentions:

SELECT c.name, o.total, p.amount
FROM dbo.customers AS c
JOIN dbo.orders AS o ON o.customer_id = c.id
JOIN dbo.payments AS p ON p.order_id = o.id AND p.customer_id = c.id;

Use APPLY when a subquery needs the outer row

CROSS APPLY (or OUTER APPLY, to keep rows with no match) runs the subquery once per outer row, so it can refer to c:

SELECT c.name, x.orders
FROM dbo.customers AS c
CROSS APPLY (SELECT COUNT(*) AS orders FROM dbo.orders AS o WHERE o.customer_id = c.id) AS x;

Reproduce it

On SQL Server 2022 (16.0.4295.3) with sqlcmd, a scratch schema with customers and orders, each statement in its own batch:

SELECT customers.name FROM seo_err_mssql.customers AS c;
SELECT c.name, o.total FROM seo_err_mssql.customers AS c
  JOIN seo_err_mssql.orders AS o ON o.customer_id = cust.id;
UPDATE seo_err_mssql.orders SET status = 'vip'
  WHERE customers.name = N'Ada' AND orders.customer_id = customers.id;
Msg 4104, Level 16, State 1, Server 7732422b7f56, Line 1
The multi-part identifier "customers.name" could not be bound.
Msg 4104, Level 16, State 1, Server 7732422b7f56, Line 1
The multi-part identifier "cust.id" could not be bound.
Msg 4104, Level 16, State 1, Server 7732422b7f56, Line 2
The multi-part identifier "customers.name" could not be bound.
Msg 4104, Level 16, State 1, Server 7732422b7f56, Line 2
The multi-part identifier "customers.id" could not be bound.

The UPDATE reported both unbound names. SELECT seo_err_mssql.customers.name FROM seo_err_mssql.customers worked, and failed with "seo_err_mssql.customers.name" once the table had the alias c. A comma join followed by a JOIN whose ON used c.id, and an ON that used o.id before orders was joined:

Msg 4104, Level 16, State 1, Server 7732422b7f56, Line 3
The multi-part identifier "c.id" could not be bound.
Msg 4104, Level 16, State 1, Server 7732422b7f56, Line 3
The multi-part identifier "o.id" could not be bound.

Rewritten with every join in order, the query returned its row. A derived table counting WHERE o.customer_id = c.id failed on "c.id"; the same subquery in CROSS APPLY returned 2, 1 and 0 orders for the three customers. UPDATE o … FROM … JOIN changed Ada’s two orders, inside a transaction that was rolled back. SQL Server 2019 and 2025 printed the same messages.

In Inlet

The query editor completes table and column names from the live schema. When SQL Server rejects the batch, Inlet shows its message with SQL Server error 4104, state 1, severity 16 and links to this page. With your own Anthropic API key, Ask Claude (Pro, ⌘L) can fix a failed statement; it sends the schema and the SQL, never rows.

Inlet: a database client for the Mac

One native app for PostgreSQL, MySQL, SQL Server, SQLite, MongoDB and Redis. It explains errors where they happen, holds your edits until you save them, and keeps production read-only until you say so.

Version 0.1.0 · macOS 26 Tahoe or later · Apple silicon and Intel