Reputation: 1278
We have users in our system that have contacts attached to them. So we implemented this by having a foreign key in our contacts table that pointed back to its owning user in the users table. But now we need to add functionality that requires a user to have a default contact. So I have added a column for the default contact of a user that points to the contacts table as a foreign key. Note the tables below.
The two tables (I have chopped them down to the relevant columns):
users table:
user_id varchar(20) PK
default_contact bigint FK to contacts.id (nullable)
contacts table:
id bigint PK
user_id varchar(20) FK to users.user_id
Notice the circular Foreign Keys.
Now I want to add a constraint to the users table that says that the default_contact can only be a contact that belongs to that user (ie. the contact's user_id == the user_id of the user who has it as a default contact). I am now stuck because I am unsure how to add this constraint. This potentially could be solved by an assertion, but as I am using SqlServer assertions are not supported. This must be a common problem, because this is the second time in two days that we have come across a similar scenario in two completely different cases.
So is it even possible to add this constraint? If so, how would I go about doing so?
So I have found one way I can do this, which is to add the constraint in via checks in a stored procedure. This will work as long as we always access the users.default_contact field via stored procedure, but I was wondering if there are any other strict solutions.
Upvotes: 0
Views: 306
Reputation: 14820
In SQL Server
you could use a combination of techniques to achieve this. A common one would be using a combination of Check Constraints and User-Defined Functions. This way when you add the constraint to the users table, everytime you perform an INSERT
or UPDATE
statement the constraint will validate the value specified for the default contact.
Firstly you will need to create the function...
create function ValidateContact(@userid int, @contact int)
returns bit
as
begin
declare @count int,
@retVal bit;
select @count = count(*) from dbo.contacts where user_id = @userid and id = @contact
if @count = 0 and @contact is not null
set @retVal = 0;
else
set @retVal = 1;
return @retVal;
end
go
This function will receive two parameters (userid and contact) and then checks whether the contact exists for the user. If it doesn't, it returns 0 (false) otherwise it returns 1 (true). The you will need to create the CHECk
constraint...
alter table dbo.users
add constraint chk_default_contact
check (dbo.ValidateContact(user_id, default_contact) = 1)
go
Now, everytime you perform an INSERT
or UPDATE
statement the CHECK
constraint will validate the input based on the logic specified in the ValidateContact
function, if the validation fails, an error is thrown and the transaction is aborted.
Hope it helped
Upvotes: 2