Click here to Skip to main content
15,888,803 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Please forgive the general nature of this question, but I am struggling to find good advice on how to handle this problem.

Assume I have two SQL tables, as follows:

Employees: id, name, department_id
1, 'John', 1
2, 'Mary', 3
3, 'Cathy', 2
4, 'Karen', 1

Departments: id, name
1, 'Sales'
2, 'Admin'
3, 'Shop floor'

When I create a new employee, I would like to allow the user of the application to leave the department blank to begin with. But when I create the database record, I obviously have to supply a department_id foreign key value. At the moment, I am using -1, which can never be a legal foreign key.

My problem comes when trying to write the SQL to retrieve all the unique employees with no duplicates.

If I simply use...

SQL
SELECT e.id, e.name, d.department FROM Employees e INNER JOIN Departments d ON e.department_id = d.id;


...then I don't get any of the new employees (i.e. the ones who have not yet been assigned a department). This means the user of the application can't access these new employees and put them in a department.

If on the other hand, I use...

SQL
SELECT e.id, e.name, d.department FROM Employees e INNER JOIN Departments d ON e.department_id = d.id OR e.department_id = -1;


...I get lots of duplicate records because every employee with no department is included in the result once for each department.

I would really appreciate some advice on how best to tackle this.

What I have tried:

I have tried adding a dummy department as the first record and assigning new employees to that, but then I have to filter this out from the UI when I am doing things like presenting a list of departments, which seems less than ideal.
Posted
Updated 2-Dec-16 7:49am

1 solution

Change the department_id column in the Employees table to be nullable, and use NULL to indicate that a department has not been assigned. This will allow you to create the foreign key reference between the two tables.
SQL
ALTER TABLE Employees
ALTER COLUMN department_id int NULL;
GO
UPDATE Employees
SET department_id = NULL
WHERE department_id = -1;
GO
ALTER TABLE Employees WITH CHECK
ADD CONSTRAINT FK_Employees_Department
FOREIGN KEY (department_id)
REFERENCES Departments (id);
GO
ALTER TABLE Employees
CHECK CONSTRAINT FK_Employees_Department;
GO


When you want to retrieve the records, use a LEFT JOIN:
SQL
SELECT 
    e.id, 
    e.name, 
    d.department
FROM
    Employees As e
    LEFT JOIN Departments As d
    ON d.id = e.department_id
;

Employee records with no department assigned will return NULL for the department column.

Visual Representation of SQL Joins[^]
 
Share this answer
 
v2
Comments
Patrick Skelton 3-Dec-16 5:02am    
Thank you very much for that. I'm very much an SQL-Learner and it would have taken me a while to remember the section I read on LEFT JOIN in my book.

I should have mentioned that I am using SQLite. According to the docs, SQLite foreign keys can be null by default, unless you add the NOT NULL to the column definition, so my tables should be okay as they stand.

My problem now is that I can't figure out how to get DBNull to be accepted as a parameter from C# into a SQLiteCommand. Various casts on DBNull.Value don't work.

I'll keep trying and post back if I find something that works.
Patrick Skelton 3-Dec-16 5:47am    
Okay, this is maybe not too elegant but it appears to work. Thank you again.

sqlCommand.Parameters.AddWithValue( "FK_Contact", ( ContactID == -1 ) ? (object)DBNull.Value : ContactID );
Patrick Skelton 3-Dec-16 5:50am    
PS - Any chance of an up-vote on my question? Surely it will be of use to other learners, and I did put some effort into it being written reasonably well.

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900