You can use COALESCE for that, but I recommend you redesign this.
T-SQL allows to use the same column of one table as foreign key in two constraints to two other tables, but if you do so, referential integrity tests are done for both tables, so a key you store in Col3 would be checked to exist in both user and group table, so it would have double meaning as both and if you had unique keys non overlapping in users and groups so one value can only be either user or group and not both, you couldn't store that as foreign key.
So in short, this is not foreseen, to have a polymorühic association you would need two foreign key fields and define the constraint only one of them is allowed to be non-NULL or better use a parent table to users and groups like in this model:
Code:
CREATE TABLE permissibles (ID integer identity(1,1)
, CONSTRAINT PK_permissibles PRIMARY KEY (ID));
CREATE TABLE users (id integer identity(1,1), permissibleID int, name varchar(50)
, CONSTRAINT PK_users PRIMARY KEY (ID)
, CONSTRAINT FK_permissibleuser FOREIGN KEY (permissibleID)
REFERENCES permissibles (ID)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE groups (id integer identity(1,1), permissibleID int, name varchar(50)
, CONSTRAINT PK_groups PRIMARY KEY (ID)
, CONSTRAINT FK_permissiblegroup FOREIGN KEY (permissibleID)
REFERENCES permissibles (ID)
ON DELETE CASCADE
ON UPDATE CASCADE);
CREATE TABLE permissions (id integer identity(1,1), permissibleID int
, CONSTRAINT PK_permissions PRIMARY KEY (ID)
, CONSTRAINT FK_permissible FOREIGN KEY (permissibleID)
REFERENCES permissibles (ID)
ON DELETE CASCADE
ON UPDATE CASCADE);
And then this data and final query:
Code:
declare @permissible as int;
insert into [dbo].[permissibles] DEFAULT VALUES;
select @permissible = SCOPE_IDENTITY();
insert into [dbo].[users] values (@permissible, 'user1');
insert into [dbo].[permissibles] DEFAULT VALUES;
select @permissible = SCOPE_IDENTITY();
insert into [dbo].[users] values (@permissible, 'user2');
insert into [dbo].[permissibles] DEFAULT VALUES;
select @permissible = SCOPE_IDENTITY();
insert into [dbo].[groups] values (@permissible, 'group1');
insert into [dbo].[permissibles] DEFAULT VALUES;
select @permissible = SCOPE_IDENTITY();
insert into [dbo].[groups] values (@permissible, 'group2');
insert into [dbo].[permissions] values (1),(2),(3),(4);
select p.*, coalesce(g.name, u.name) as [user or group] from [dbo].[permissions] p
inner join [dbo].[permissibles] pi on p.permissibleid = pi.id
left join [dbo].[users] u on u.permissibleid = pi.id
left join [dbo].[groups] g on g.permissibleid = pi.id
The permission can be on users or usergroups, so they don't reference users and groups directly but via the permissibles table, to which each user or group has an association. You join through permissibles and find either a user or a group, never both (by the way the keys are generated). Permissibles has no data at all, you might add columns, but it's really just a polymorühic association key table.
The main ingredient is using coalesce, you can also use that in your design, but notice you then can't make use of foreign key constraints as the SQL Server implements them. It would almost be sufficient if permissibles would be a sequence instead of a table, but you can't define constraints to a sequence and join through it.
Bye, Olaf.
PS: You might wonder why having separate user and group primary keys if their permissibleID also is unique by definition. Well, you might have other relationships with only users or only groups and that better goes via direct relationship without going through permissibles.
Now you might use a permissibles.ID in both users and groups, but shouldn't unless you want a group to be that user only. There is no way to constrain a permissibles.ID to be only used in one of the two tables but the way you generate them and use them in only one table. You can and perhaps should also have the users.permissibleID and groups.permissibleID have a unique constraint, too. And obviously, you can also have a traditional association of users with groups by a groupusers table (ID, groupID, userID).
Olaf Doschke Software Engineering