There are cases where a SQL Server database developer might get an error message similar to: “The multi part identifier could not be bound“. This happens because of the way the database developer handles table scopes within the query. Read the article below, in order to better understand this error, and see how easy is to resolve it via a simple example.
Reproducing the “Multi Part Identifier Could not be Bound” Error Message
Let’s see below, a relevant example that reproduces the above error message.
Consider two tables; table Employee and table Address.
Employee table:
CREATE TABLE [dbo].[Employee]( [id] [int] NOT NULL, [name] [varchar](50) NULL, [age] [int] NULL ) ON [PRIMARY]
Address table
CREATE TABLE [dbo].[address]( [empid] [int] NOT NULL, [street] [varchar](50) NULL, [city] [varchar](50) NULL, [country] [varchar](50) NULL ) ON [PRIMARY]
Let’s say we want to write a query returning all the employees and their country of residence sorted by the latter alphabetically.
A suggested query would be the following:
SELECT emp.name AS EmployeeName , addr.country AS EmployeeCountry FROM [Employee] emp INNER JOIN [Address] addr ON emp.id = addr.empID ORDER BY addr.country ASC;
Indeed, the above query works fine.
Though if someone tried to get the employees’ country using a subquery like this:
SELECT emp.name AS EmployeeName , ( SELECT addr.country FROM [Address] addr WHERE addr.empID = emp.id ) AS EmployeeCountry FROM [Employee] emp ORDER BY addr.country ASC; GO
… then he/she would end up with the following error:
The multi-part identifier “addr.country” could not be bound.
Learn more tips like this! Enroll to our Online Course!
Check our online course titled “Essential SQL Server Development Tips for SQL Developers” (special limited-time discount included in link).
Sharpen your SQL Server database programming skills via a large set of tips on T-SQL and database development techniques. The course, among other, features over than 30 live demonstrations!
(Lifetime Access/ Live Demos / Downloadable Resources and more!) Enroll from $14.99
Explaining and Resolving the Error
The problem in the above T-SQL Statement is that even though we used “addr” as a table alias in the subquery, we are not syntactically allowed to use it outside the scope of the subquery which, in this example, is in the order by clause. Though the opposite is possible, that is to reference a table/alias of an outer query within an internal query (subquery). That is why in our subquery we are able to reference the emp.id table/column.
For eliminating the above error and keep on using the subquery, the correct code for this case would be:
SELECT emp.name AS EmployeeName , ( SELECT addr.country FROM [Address] addr WHERE addr.empID = emp.id ) AS EmployeeCountry FROM [Employee] emp ORDER BY EmployeeCountry; GO
Analysis and Discussion
Even though in this example the problem was obvious, in many cases where we develop some really large and complex queries along with subqueries, we might end up consuming valuable time for resolving such issues 🙂
To this end we should always be careful when using subqueries in our T-SQL statements and always keep in mind that subqueries can only provide their results to their outer queries and not references to the subqueries’ tables.
A future post will thoroughly explain the usage of subqueries in SQL Server.
Watch video: The Multi Part Identifier Could not be Bound – How to Resolve in SQL Server
Featured Online Courses:
- SQL Server 2022: What’s New – New and Enhanced Features [New]
- Data Management for Beginners – Main Principles
- Introduction to Azure Database for MySQL
- Working with Python on Windows and SQL Server Databases
- Boost SQL Server Database Performance with In-Memory OLTP
- Introduction to Azure SQL Database for Beginners
- Essential SQL Server Administration Tips
- SQL Server Fundamentals – SQL Database for Beginners
- Essential SQL Server Development Tips for SQL Developers
- Introduction to Computer Programming for Beginners
- .NET Programming for Beginners – Windows Forms with C#
- SQL Server 2019: What’s New – New and Enhanced Features
- Entity Framework: Getting Started – Complete Beginners Guide
- A Guide on How to Start and Monetize a Successful Blog
- Data Management for Beginners – Main Principles
Check some other related error messages and ways to resolve them:
- Error converting data type varchar to float
- Operating System Error 170 (Requested Resource is in use)
- Installing SQL Server 2016 on Windows Server 2012 R2: Rule KB2919355 failed
- A connection was successfully established with the server, but then an error occurred during the login process.
- There is insufficient system memory in resource pool ‘internal’ to run this query.
- Argument data type ntext is invalid for argument …
- Could not load file or assembly ‘Microsoft.SqlServer.Smo, Version=10.0.0.0, …
- Fix: VS Shell Installation has Failed with Exit Code 1638
- The OLE DB provider “Microsoft.ACE.OLEDB.12.0” has not been registered – How to Resolve it
- Introduction to Azure Database for MySQL (Course Preview)
- SQL Server replication requires the actual server name to make a connection to the server – How to Resolve it
- Issue Adding Node to a SQL Server Failover Cluster – Greyed Out Service Account – How to Resolve
- Resolve SQL Server CTE Error – Incorrect syntax near ‘)’.
- SQL Server is Terminating Because of Fatal Exception 80000003 – How to Troubleshoot
- … more SQL Server troubleshooting articles
Subscribe to our newsletter and stay up to date!
Check out our latest software releases!
Check our eBooks!
Rate this article: (8 votes, average: 5.00 out of 5)
Loading…
Reference: SQLNetHub.com (https://www.sqlnethub.com)
© SQLNetHub
The Multi Part Identifier Could not be Bound
Click to Tweet
Artemakis Artemiou is a Senior SQL Server Architect, Author, a 9 Times Microsoft Data Platform MVP (2009-2018). He has over 20 years of experience in the IT industry in various roles. Artemakis is the founder of SQLNetHub and {essentialDevTips.com}. Artemakis is the creator of the well-known software tools Snippets Generator and DBA Security Advisor. Also, he is the author of many eBooks on SQL Server. Artemakis currently serves as the President of the Cyprus .NET User Group (CDNUG) and the International .NET Association Country Leader for Cyprus (INETA). Moreover, Artemakis teaches on Udemy, you can check his courses here.
Views: 12,781
- Remove From My Forums
-
Вопрос
-
Hi I am receiving the following error: «The multi-part identifier «v_Dept.depts» could not be bound» when running the following SQL code:
select v_Dept.depts AS [Department], [1] AS January, [2] AS Febrary, [3] AS March, [4] AS April, [5] AS May, [6] AS June, [7] AS July, [8] AS August, [9] AS September, [10] AS October, [11] AS November, [12] AS December from ( SELECT datepart(mm, cmtrp.mnth) AS my_month, v_Dept.depts AS [Department] FROM v_Dept RIGHT OUTER JOIN cmatp ON v_Dept.ds_reckey = camatp.mg_depart LEFT OUTER JOIN cclient ON camatp.mg_client = caclient.cl_accode WHERE (caclient.cl_clgrp IN ('YOUR', 'NEWHA', 'EWM')) AND (CAST(cmatp.datopn AS datetime) BETWEEN CAST('2011-05-01 00:00:00.000' AS datetime) AND CAST('2014-04-30 00:00:00.000' AS datetime)) OR (CAST(cmatp.datopn AS datetime) BETWEEN CAST('2011-05-01 00:00:00.000' AS datetime) AND CAST('2014-04-30 00:00:00.000' AS datetime)) AND (client.cl_code IN ('00000075', '00071667', '00001204')) ) AS t PIVOT ( COUNT([Department]) FOR my_month IN([1], [2], [3], [4], [5],[6],[7],[8],[9],[10],[11],[12]) ) p
It is something to do with how I am structuring my SQL code but I can’t for the life of me figure out how I rewrite this despite me knowing I have done this for previous reports!
Can somebody please help? Thanks, Dan
Ответы
-
Please re-read all my replies one more time carefully.
Once again.
1. Start with the query you currently have as subquery (the one you aliased as t). Make sure it works and returns Department, my_Month, someOtherColumn.
2. Once you have that query working for you correctly (no typos), turn this query into CTE (common table expression for simplicity), e.g.
;with cte as (here goes the working query)
select * from cte — one more check
The ; before cte is important and should not be omitted.
3. If you have select * from cte working, then proceed with your final query that should be
select * from cte PIVOT (count(SomeOtherColumn)
for my_month in ([January], [February], etc.)) pvt
——————
I suggest to get my_month using the name of the month, e.g. DATENAME function, this way you would not need changing [1], [2], etc. into English month names and can simply use select *
—————
That’s all what is needed here and if you can follow this simple plan, you’ll get your PIVOT working.
-
Изменено
20 июля 2015 г. 15:32
-
Помечено в качестве ответа
Dan Rooney
21 июля 2015 г. 9:45
-
Изменено
-
Please re-read all my replies one more time carefully.
Once again.
1. Start with the query you currently have as subquery (the one you aliased as t). Make sure it works and returns Department, my_Month, someOtherColumn.
2. Once you have that query working for you correctly (no typos), turn this query into CTE (common table expression for simplicity), e.g.
;with cte as (here goes the working query)
select * from cte — one more check
The ; before cte is important and should not be omitted.
3. If you have select * from cte working, then proceed with your final query that should be
select * from cte PIVOT (count(SomeOtherColumn)
for my_month in ([January], [February], etc.)) pvt
——————
I suggest to get my_month using the name of the month, e.g. DATENAME function, this way you would not need changing [1], [2], etc. into English month names and can simply use select *
—————
That’s all what is needed here and if you can follow this simple plan, you’ll get your PIVOT working.
Thank you, thank you, thank you Naomi!! This is pretty much my working query for those wanting to know…
;with cte as
(
SELECT datepart(mm, camgrp.datopn) AS my_month, v_Dept.depts AS [Department], another_column
FROM v_Dept
RIGHT OUTER JOIN camgrp ON v_Department.ds_reckey = camgrp.mg_depart
LEFT OUTER JOIN client ON camgrp.mg_cli = client.cl_code
WHERE (client.clgrp IN (‘YOUR’, ‘EWM’))
)
SELECT * FROM ctePIVOT (
COUNT([another_column])
FOR my_month IN([1], [2], [3], [4], [5],[6],[7],[8],[9],[10],[11],[12])
) pWHERE [Department] IS NOT NULL
-
Помечено в качестве ответа
Eric__Zhang
27 июля 2015 г. 9:49
-
Помечено в качестве ответа
- Remove From My Forums
-
Question
-
Hi,
When I try execute one query in SQL 2k5, with alias in order by clausule, I retrieve the follow message:
Server: Msg 4104, Level 16, State 1, Line 1
The multi-part identifier «alias.fields» could not be bound.Where alias is a any alias and, fields is a field of the table with alias.
Already exists one fix to patch this?
Thanks
Answers
-
In your select statement there is no reference to this table (rentalCostTable), so that’s why you’re getting the error:
SELECT locationTypesTable.locationTypes, rentalCostTable.rentalCost, PFR.shortDescription, PFR.propertyRef, propertyTypesTable.propertyType, PFR.numBeds FROM propertysForRentTable PFR INNER JOIN propertyTypesTable ON PFR.typeOfProperty = propertyTypesTable.keyID INNER JOIN locationTypesTable ON PFR.location = locationTypesTable.keyID
In order to resolve the error, you must include this table in the FROM clause, e.g. JOIN with it based on some field.
SELECT locationTypesTable.locationTypes, rentalCostTable.rentalCost, PFR.shortDescription, PFR.propertyRef, propertyTypesTable.propertyType, PFR.numBeds FROM propertysForRentTable PFR INNER JOIN propertyTypesTable ON PFR.typeOfProperty = propertyTypesTable.keyID INNER JOIN locationTypesTable ON PFR.location = locationTypesTable.keyID INNER JOIN rentalCostTable ON PFR.RentalID = rentalCostTable.RentalID -- use the actual field to join the tables
Premature optimization is the root of all evil in programming. (c) by Donald Knuth
Naomi Nosonovsky, Sr. Programmer-Analyst
My blog
-
Marked as answer by
Wednesday, September 15, 2010 11:25 PM
-
Marked as answer by
-
This was a bug in the older versions of SQL Server. We fixed the problems with the ORDER BY clause in SQL Server 2005. This is documented under the following topic:
You should also check out the other backward compatibility topics:
Also, I should note that the query above will run fine if the database compatibility level is set to 80 or below. You can do this by using the sp_dbcmptlevel system SP but please read the corresponding topic in Books Online before going this route. The database compatibility level for databases upgraded from SQL Server will automatically be at 80 so your existing code should run fine.
-
Greetings. I ran into this because I had alias conflicts where the table name and the field name were the same. Once I gave the table a true alias (e.g. «z3») with no conflict,
it worked fine.UPDATE #LocTracker
SET ErrorCode
= 3
—‘Unknown ZIP3’FROM #LocTracker lt
LEFT
OUTER
JOIN US_TC_RMS_DB_MGMT..ZIP3
ON zip3.ZIP3
=
LEFT(lt.POSTALCODE,3)WHERE lt.POSTALCODE
is
nullAND ErrorCode
= 0
Gave me this error:
The multi-part identifier «zip3.ZIP3» could not be bound.
Certainly zip3.ZIP3 referencing is not Best Practices.
UPDATE can be very tricky. Note above that #LocTracker is used after the UPDATE then after the FROM with alias. While valid T-SQL, I always found it confusing.
Referring to the sample below, I just put the table name with alias after FROM, and
after UPDATE I use the table alias. I also use table alias for each column.Same consideration if you are JOINing to subselect (derived table).
The advantage of such an approach is that you take out the guesswork from the query.
You tell precisely the database engine what should it do.
USE tempdb; SELECT * INTO SOH FROM AdventureWorks2008.Sales.SalesOrderHeader SELECT * INTO SOD FROM AdventureWorks2008.Sales.SalesOrderDetail -- Bad reference I meant to type b.ProductID UPDATE a SET a.TotalDue = a.TotalDue * 1.05 FROM SOH a INNER JOIN SOD b ON a.SalesOrderID = b.SalesOrderID WHERE c.ProductID != 800 GO /* Msg 4104, Level 16, State 1, Line 12 The multi-part identifier "c.ProductID" could not be bound. */ -- Correct reference, successful query UPDATE a SET a.TotalDue = a.TotalDue * 1.05 FROM SOH a INNER JOIN SOD b ON a.SalesOrderID = b.SalesOrderID WHERE b.ProductID != 800 GO -- (31366 row(s) affected) DROP TABLE SOH DROP TABLE SOD
Kalman Toth
New Book:
Beginner Database Design & SQL Programming Using Microsoft SQL Server 2016-
Marked as answer by
Kalman Toth
Tuesday, November 15, 2011 9:25 PM -
Edited by
Kalman Toth
Friday, November 10, 2017 10:03 AM
-
Marked as answer by
-
Mine was a total bonehead mistake. I mis-spelled the table name in the SELECT field.
IntelliSense may be helpful (starting with SQL Server 2008):
-
Marked as answer by
Kalman Toth
Tuesday, November 15, 2011 9:24 PM -
Edited by
Kalman Toth
Thursday, November 9, 2017 1:08 AM
-
Marked as answer by
-
-
Proposed as answer by
Naomi N
Tuesday, December 14, 2010 7:16 PM -
Marked as answer by
Kalman Toth
Wednesday, March 30, 2011 1:07 AM -
Edited by
Kalman Toth
Thursday, November 9, 2017 1:08 AM
-
Proposed as answer by
Home > SQL Server Error Messages > Msg 4104 — The multi-part identifier could not be bound. |
||
SQL Server Error Messages — Msg 4104 — The multi-part identifier could not be bound. |
||
To illustrate, given the following table structure: CREATE TABLE [dbo].[Employee] ( [EmployeeID] INT [FullName] VARCHAR(100), [ManagerID] INT ) The following SELECT statement will generate the error: SELECT [Manager].[FullName] AS [ManagerName], [Emp].[EmployeeID], [Emp].[FullName] FROM [dbo].[Employee] [Emp] INNER JOIN [dbo].[Employee] [Mgr] ON [Emp].[ManagerID] = [Mgr].[EmployeeID] Msg 4104, Level 16, State 1, Line 1 The multi-part identifier "Manager.FullName" could not be bound. The error is encountered because there is no [Manager] table or alias defined in the FROM clause. Another way of getting the error is when an alias has been assigned to a table referenced in the FROM clause of a statement and the table is used as a prefix of a column instead of using the alias. To illustrate, here’s another way of getting the error: SELECT [Employee].[EmployeeID], [Emp].[FullName] FROM [dbo].[Employee] [Emp] Msg 4104, Level 16, State 1, Line 1 The multi-part identifier "Employee.EmployeeID" could not be bound. Since an alias has already been used for the [dbo].[Employee] table, the alias, in this case [Emp], should be used instead of the table name when used as a prefix in the column names. The error can also happen not just as part of the column list in the SELECT statement but can also happen when the referenced column is in the JOIN clause, WHERE clause or the ORDER BY clause. -- As part of the JOIN clause SELECT [Mgr].[FullName] AS [ManagerName], [Emp].[EmployeeID], [Emp].[FullName] FROM [dbo].[Employee] [Emp] INNER JOIN [dbo].[Employee] [Mgr] ON [Emp].[ManagerID] = [Manager].[EmployeeID] -- As part of the ORDER BY clause SELECT [Mgr].[FullName] AS [ManagerName], [Emp].[EmployeeID], [Emp].[FullName] FROM [dbo].[Employee] [Emp] INNER JOIN [dbo].[Employee] [Mgr] ON [Emp].[ManagerID] = [Mgr].[EmployeeID] ORDER BY [Manager].[FullName] Solution / Workaround: This error can easily be avoided by making sure that the table or alias used when qualifying columns in the SELECT statement matches one of the tables or aliases specified in the FROM clause. In the first scenario, simply change the incorrect alias used in the SELECT statement. Changing the [Manager] prefix, which doesn’t exist in the FROM clause, to [Mgr] will solve the issue: SELECT [Mgr].[FullName] AS [ManagerName], [Emp].[EmployeeID], [Emp].[FullName] FROM [dbo].[Employee] [Emp] INNER JOIN [dbo].[Employee] [Mgr] ON [Emp].[ManagerID] = [Mgr].[EmployeeID] In the second scenario, since an alias has already been assigned to the table, use that alias instead of the table when prefixing columns from then on. Changing the [Employee] table prefix to the [Emp] alias will solve the issue: SELECT [Emp].[EmployeeID], [Emp].[FullName] FROM [dbo].[Employee] [Emp] |
||
Related Articles : | ||