InletDownload

SQL Server error 207

Invalid column name (SQL Server error 207)

SQL Server couldn’t find a column with that name in the tables your statement uses. Usually it’s a typo or the wrong table, but a string in double quotes, a SELECT alias used in WHERE, and a column added earlier in the same batch all give the same error.

Invalid column name 'ownr'.

Tested on SQL Server 2022 (16.0.4295.3); also 2019 (15.0.4490.9) and 2025 (17.0.5005.3) · Updated 9 October 2026

What it means

When SQL Server compiles a statement, it looks up every column name in the tables, views and derived tables the statement names. Error 207 means one of them isn’t there, as written. The message gives the name it looked for:

Msg 207, Level 16, State 1, Line 1
Invalid column name 'ownr'.

The error comes at compile time, so the statement (and, for some causes, the whole batch) doesn’t run at all: nothing is half-done.

Common causes

  1. A typo, or the column is in another table. o.owner when owner is in accounts, not orders.
  2. A string in double quotes. With QUOTED_IDENTIFIER ON (the default for most drivers), "open" is a column name, not a string. Strings take single quotes: 'open'.
  3. A SELECT alias used in WHERE, GROUP BY or HAVING. SQL Server evaluates WHERE before the SELECT list, so the alias doesn’t exist yet. (ORDER BY runs after SELECT, so aliases work there.)
  4. A column added in the same batch. ALTER TABLE … ADD note followed by a statement that uses note in one batch fails: the whole batch is compiled before the ALTER runs.
  5. Case, on a case-sensitive database. With a _CS_ or _BIN collation, total and Total are different columns.
  6. The schema changed under your code: a renamed or dropped column, or a different version of the database than you think.

How to fix it

Check the column’s real name and table

SELECT c.name AS column_name, TYPE_NAME(c.user_type_id) AS type_name
FROM sys.columns AS c
WHERE c.object_id = OBJECT_ID('dbo.orders')
ORDER BY c.column_id;

EXEC sp_help 'dbo.orders'; shows the same and more. In a join, prefix every column with its table’s alias, so a column in the wrong table fails clearly and a column in both doesn’t become ambiguous.

Put strings in single quotes

SELECT id, total FROM orders WHERE status = 'open';    -- not "open"

Double quotes are for identifiers: "order date" is the same as [order date]. sqlcmd is the exception: it starts with QUOTED_IDENTIFIER OFF unless you pass -I, so "open" works there as a string and then fails in your application. Don’t rely on it.

Repeat the expression, or wrap the query

Either repeat the expression in WHERE:

SELECT id, total * 1.2 AS gross FROM orders WHERE total * 1.2 > 20;

or compute it in a derived table (or CROSS APPLY, or a CTE) and filter outside:

SELECT id, total, gross
FROM (SELECT id, total, total * 1.2 AS gross FROM orders) AS o
WHERE gross > 20;

Split the batch after ALTER TABLE

Put the ALTER TABLE in its own batch (GO after it, in tools that understand GO), or run the later statement through EXEC so it’s compiled after the column exists:

ALTER TABLE orders ADD note varchar(50) NULL;
GO
UPDATE orders SET note = 'checked';

Match the case on case-sensitive databases

Check the collation, and write names exactly as they were created:

SELECT DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS collation;

A collation with _CS_ (case-sensitive) or _BIN/_BIN2 (binary) makes identifiers case-sensitive in that database.

Reproduce it

On SQL Server 2022 (RTM-CU27, 16.0.4295.3), tables seo_sqlerr_conn.accounts (id, owner, balance) and seo_sqlerr_conn.orders (id, account_id, total, status), with sqlcmd -I (QUOTED_IDENTIFIER ON), one statement per batch:

SELECT ownr FROM seo_sqlerr_conn.accounts;
SELECT id, total FROM seo_sqlerr_conn.orders WHERE status = "open";
SELECT id, total * 1.2 AS gross FROM seo_sqlerr_conn.orders WHERE gross > 20;
SELECT o.id, o.owner FROM seo_sqlerr_conn.orders AS o JOIN seo_sqlerr_conn.accounts AS a ON a.id = o.account_id;
Msg 207, Level 16, State 1, Server 7732422b7f56, Line 1
Invalid column name 'ownr'.
Msg 207, Level 16, State 1, Server 7732422b7f56, Line 1
Invalid column name 'open'.
Msg 207, Level 16, State 1, Server 7732422b7f56, Line 1
Invalid column name 'gross'.
Msg 207, Level 16, State 1, Server 7732422b7f56, Line 1
Invalid column name 'owner'.

An ALTER TABLE and an UPDATE of the new column in one batch, inside a transaction:

BEGIN TRAN;
ALTER TABLE seo_sqlerr_conn.orders ADD note varchar(50) NULL;
UPDATE seo_sqlerr_conn.orders SET note = 'checked';
ROLLBACK;
Msg 207, Level 16, State 1, Server 7732422b7f56, Line 3
Invalid column name 'note'.

None of the batch ran: afterwards @@TRANCOUNT was 0 and COL_LENGTH('seo_sqlerr_conn.orders', 'note') was NULL, so even the ALTER hadn’t happened. The derived-table version of the alias query returned rows 1 and 2. With SET QUOTED_IDENTIFIER OFF, status = "open" returned rows 2 and 3. And sqlcmd without -I reported QUOTED_IDENTIFIER as 0 for the session.

On a temporary SQL Server 2022 container, in a database created with Latin1_General_100_CS_AS and a table dbo.Orders (Id, Total), SELECT Id, total FROM dbo.Orders got Invalid column name 'total'. (and dbo.orders got error 208). SQL Server 2019 (15.0.4490.9) and 2025 (17.0.5005.3) gave the same errors.

In Inlet

Inlet’s sidebar reads schemas, tables and views from SQL Server’s system views, and a table’s definition (its CREATE TABLE) shows every column’s exact name and case. Query tabs run T-SQL a batch at a time and GO splits batches, so an ALTER TABLE followed by GO works there as it does in sqlcmd. With your own Anthropic API key, Ask Claude (⌘L) writes T-SQL from the schema. When a statement fails with 207, the error links to this page.

Related

Sources