Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / database / SQL-Server / SQL-Server-2008

Use of columns belonging to tables referenced on main query in a subquery

5.00/5 (4 votes)
17 Feb 2011CPOL1 min read 13.6K  
Catastrophic results associated with unqualified use of columns belonging to tables referenced on main query in a subquery

Introduction

SQL server allows you to use columns of tables referenced on a main query in a subquery. I came across a scenario where this can have a catastrophic effect.

Background

Look at the statement below:


SQL
DELETE Projects WHERE EmployeeId IN (
    SELECT EmployeeId FROM Employees WHERE EmployeeType = 1)

where, [EmployeeId] is foreign key field in Projects table that references the primary key field [Id] in Employees table.
Note: There is NO field named [EmployeeId] in Employees table. This query will effectively clear the whole of your Projects table. Actually, what you intended was:


SQL
DELETE Projects WHERE EmployeeId IN (
    SELECT Id FROM Employees WHERE EmployeeType = 1)

Full Description


Step 1: Create Employees table


SQL
CREATE TABLE Employees (
    Id INT, FullName NVARCHAR(128), EmployeeType INT)

Step 2: Create Projects table


SQL
CREATE TABLE Projects (
    Id INT, EmployeeId INT, ProjectName NVARCHAR(256))

Step 3: Insert dummy data into Employees table


SQL
INSERT INTO Employees VALUES (1, N'Jeff Hardy', 1)
INSERT INTO Employees VALUES (2, N'John Gathogo', 2)
INSERT INTO Employees VALUES (3, N'Jane Doe', 1)

Step 4: Insert dummy data into Projects table


SQL
INSERT INTO Projects VALUES (1, 1, N'Project Alpha')
INSERT INTO Projects VALUES (2, 1, N'Project Beta')
INSERT INTO Projects VALUES (3, 3, N'Project Gamma')
INSERT INTO Projects VALUES (4, 2, N'Project Theta')

Step 5: Now, run the following queries, to reproduce the behaviour

  1. SQL
    SELECT * FROM Projects WHERE EmployeeId IN (
        SELECT EmployeeId FROM Employees)
  2. SQL
    SELECT * FROM Projects WHERE EmployeeId IN (
        SELECT EmployeeId FROM Employees WHERE EmployeeType = 1)
  3. SQL
    DELETE Projects WHERE EmployeeId IN (
        SELECT EmployeeId FROM Employees WHERE EmployeeType = 1)

Results

  1. 11Project Alpha
    21Project Beta
    33Project Gamma
    42Project Theta

  2. 11Project Alpha
    21Project Beta
    33Project Gamma
    42Project Theta

  3. (4 row(s) affected)

There a serious issue here - I believe that while giving you the flexibility, SQL Server should protect the user here. The Employees table has no such column named EmployeeId, and I believe it does not raise an error since the Projects table referenced on the main query has an EmployeeId field. If you look at the results,


SQL
SELECT * FROM Projects WHERE EmployeeId IN (
    SELECT EmployeeId FROM Employees)

ends up giving you the same results as:


SQL
SELECT * FROM Projects WHERE EmployeeId IN (
    SELECT EmployeeId FROM Employees WHERE EmployeeType = 1)

The issue is even more critical for the DELETE statement since you end up clearing the whole of your Projects table.

Workaround

Obviously, if one had qualified the column names, then the parser would have helped uncover the not-so-obvious error in the query. Like in,

SQL
DELETE Projects WHERE EmployeeId IN (
    SELECT Employees.EmployeeId FROM Employees WHERE Employees.EmployeeType = 1)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)