How to establish foreign key relationship - sql

I got three tables.
User
Project
WorkFlow
In workflow ProjectId, UserId together should never repeat. Thats my
requirement.I mean the combination should never repeat.
And the ProjectId should be present in the Project table and UserId
should be present in the User table.
This is the requirement.
Steps i tried :
I made ProjectId, UserId as composite key in workFlow. But cant be able to maintain foreign key since two columns are not available in single table.
How to resolve this.
I am open to change my design also, since this is the initial stage of my development.
Main reuirement is
One table to store project (project table) related informations and
the other one(workFlow) hold the record which project is assigned to
which user.

Foreign keys do not control uniqueness; they only control referential integrity. For uniqueness, you need unique constraints:
create table dbo.Workflow (
Id int identity(1,1) primary key,
ProjectId int not null,
UserId int not null,
foreign key (ProjectId) references dbo.Project (Id),
foreign key (UserId) references dbo.[User] (Id),
unique (UserId, ProjectId)
);
EDIT: If you don't need a surrogate key in this table, and don't care much about its possible children, you can simplify the structure by switching from surrogate primary key to the natural one. With table becoming more narrow, it will increase performance in high load scenarios by reducing its disk footprint:
create table dbo.Workflow (
ProjectId int not null,
UserId int not null,
primary key (UserId, ProjectId)
foreign key (ProjectId) references dbo.Project (Id),
foreign key (UserId) references dbo.[User] (Id),
);
And yes, constraints should be uniquely named, it will make schema comparisons and updates much easier.

Related

foreign key constraints forbiding cascading delete

I have teams that can be assigned team members and people. The team table and person tables already exist and can't be touched, I'm creating join tables to assign team members and team leads.
I have one key constraint, a team lead must be a team member, and as long as someone is assigned as a team lead it should be impossible to remove them as a team member.
My sql looks something like this (translating from a more complex table, forgive me if I mistyped my example since I'm writing it by hand)
CREATE TABLE TEAM_MEMBERS (id BIGINT NOT NULL,
teamId BIGINT NOT NULL,
personId BIGINT NOT NULL,
PRIMARY KEY (id),
KEY (teamId),
KEY (personId)
CONSTRAINT fk_team FOREIGN KEY (teamId) REFERENCES TEAM(id) ON DELETE CASCADE);
CREATE TABLE TEAM_LEAD (id BIGINT NOT NULL,
teamId BIGINT NOT NULL,
personId BIGINT NOT NULL,
PRIMARY KEY (id),
KEY (teamId),
KEY (personId),
CONSTRAINT fk_team_u FOREIGN KEY (teamId) REFERENCES TEAM (id) ON DELETE CASCADE,
CONSTRAINT fk_child FOREIGN KEY (teamId, personId) REFERENCES TEAM_MEMBERS(teamId, personId)) ON DELETE RESTRICT;
This does not work. When a team is removed I get a constraint violation, because it cascades the delete to team_members first, attempts to delete that, and discovers that team_lead is blocking it.
My question, is there an easy way express some sort of order of operations here, to make sql understand that it should remove the team-lead first, or otherwise understand that it is not a constraint violation if it cascades the deletes entirely?
I realize one solution would be to make teamLead a boolean on team_members rather then a separate join table. For various reasons I would prefer not to do this, but it can be done if there is not another cleaner solution.
Were using PostgreSQL on server, H2 for our testing, though we would prefer not to be tied in to a DB if possible.
This SQL constraint should not be here:
CONSTRAINT fk_child FOREIGN KEY (teamId, personId) REFERENCES TEAM_MEMBERS(teamId, personId)) ON DELETE RESTRICT;
Your data model seems wrong: a team leader should not have a foreign key pointing to team members, but to a team only.
Could you please post the complete schema so we could provide a more complete answer?

SQL Table Schema For Sub Product Types

I have a traditional SQL schema with Supplier ==> Product relationship.
However, I also have a couple of 'super' product types that warrant their own data/tables. I've come up with the following schema - bear in mind that I'm using Entity Framework, so navigation is also important to me.
The only duplication is on the niche product table, where SupplierID has been added to maintain a relationship with NicheSupplier.
NicheSupplier is required because there is some additional information, that only niche suppliers have based on having 1 or more niche products.
If necessary, I can add a relationship directly with Supplier too (good for EF nav).
I've identified athat a couple of triggers will also be necessary to the niche tables to ensure integrity.
I'm no SQL expert - in fact, far from it, so I would appreciate comments and advice as to whether there are better patterns for this type of scenario, or there is anything inheritently bad.
Your schema is close, but not quite there, you do need the link from dbo.NicheProduct.SupplierID to dbo.NicheSupplier.SupplierID, but you also need to add the link from dbo.Product to dbo.NicheProduct, to ensure that the combination of supplier and product id in NicheSupplier is a valid combination. To do this you need to add a Unique constraint to dbo.Prodcut on (ProductID, SupplierID), this allows a foreign key on NicheProduct ensuring that the combination is valid. This means that triggers are not required to maintain integrity. So your SQL would look something like:
CREATE TABLE dbo.Supplier
(
ID INT IDENTITY,
CONSTRAINT PK_Supplier__ID PRIMARY KEY (ID)
);
CREATE TABLE dbo.NicheSupplier
(
SupplierID INT NOT NULL,
CONSTRAINT PK_NicheSupplier__SupplierID PRIMARY KEY (SupplierID),
CONSTRAINT FK_NicheSupplier__SupplierID FOREIGN KEY (SupplierID)
REFERENCES dbo.Supplier (ID)
);
CREATE TABLE dbo.Product
(
ID INT IDENTITY,
SupplierID INT NOT NULL,
CONSTRAINT PK_Product__ID PRIMARY KEY (ID),
CONSTRAINT FK_Product__SupplierID FOREIGN KEY (SupplierID)
REFERENCES dbo.Supplier (ID),
CONSTRAINT UQ_Product__ID_SupplierID UNIQUE (ID, SupplierID)
);
CREATE TABLE dbo.NicheProduct
(
ProductID INT NOT NULL,
SupplierID INT NOT NULL,
CONSTRAINT PK_NicheProduct__ProductID PRIMARY KEY (ProductID),
CONSTRAINT FK_NicheProduct__ProductID_SupplierID FOREIGN KEY (ProductID, SupplierID)
REFERENCES dbo.Product (ID, SupplierID),
CONSTRAINT FK_NicheProduct__SupplierID FOREIGN KEY (SupplierID)
REFERENCES dbo.NicheSupplier (SupplierID)
);

Using a foreign key as part of a composite primary key

I have two tables in SQL Server. The first is all the 1:1 relationships that belong to individual jobs, which has the primary key declared as follows:
CREATE TABLE Jobs(
JobNumber bigint PRIMARY KEY )
The second table is the list of all of the jobs' components and their 1:1 relationships.
Each component refers to a single job by its job number, which is a foreign key, and multiple components may refer to the same job. Components are numbered within jobs as 1, 2, 3 and so on.
Is it possible and reasonable to use the column JobNumber (foreign key) within a composite primary key in the 2nd table, so that the primary key would be made up of (JobNumber, ComponentNumber) as follows:
CREATE TABLE Components(
JobNumber bigint FOREIGN KEY REFERENCES Jobs(JobNumber) NOT NULL,
ComponentNumber int NOT NULL,
PRIMARY KEY(JobNumber, ComponentNumber)
)
The other option is, of course, to use a surrogate primary key, but this would not enforce the uniqueness constraint on the combination of JobNumber and ComponentNumber (two records in the 2nd table could have JobNumber=1 and ComponentNumber=1, for example), so I would prefer to use a composite natural primary key.
Sure, why not? I don't see any reason not to use the composite primary key!
The only minor drawback is that any other table that needs to reference your Components table now also must use both columns to establish a foreign key relationship - you cannot reference only half of the primary key of a table.
Also: if you would choose to use a separate surrogate column as your PK, you can always enforce uniqueness with a unique constraint on (JobNumber, ComponentNumber) ....

Referential integrity over table portion

I'm designing a database and can't figure out how to model referential integrity.
I have the following tables
CREATE TABLE Groups
(
GroupId INT PRIMARY KEY,
GroupName VARCHAR(50)
)
CREATE TABLE GroupMembers
(
GroupId INT NOT NULL,
MemberId INT NOT NULL,
MemberName VARCHAR(50),
CONSTRAINT pk_GroupMember PRIMARY KEY (GroupId, MemberId)
)
CREATE TABLE Missions
(
MissionId INT PRIMARY KEY,
GroupId INT NOT NULL,
MissionName VARCHAR(50)
)
CREATE TABLE MissionRollAssignments
(
MissionId INT NOT NULL,
MemberId INT NOT NULL,
MemberRoll VARCHAR(50) --This will probably become RollId and move details to another table
)
Every mission will have assignments for some/all members of the corresponding group. There will be several missions associated with each group, but only one mission per group is active at a given time.
My question is:
Is it possible to enforce referenciay integrity for roll assignments such that only members
of the corresponding group (given by the MissionId) are selected? I know I can filter this from the GUI, but I'd feel more comfortable if I could create a FK constraint from MissionRollAssignments to GroupMembers while considering the GroupId indicated in the Mission.
A second question would be if you guys think this is a good way to model my domain, or maybe I should try a different approach.
Thanks in advance for any help on this.
Best regards,
Awer
You could put GroupId into MissionRollAssignments and then add two constraints as follows:
ALTER TABLE MissionRollAssignments
ADD CONSTRAINT fk1 FOREIGN KEY (GroupId, Memberid)
REFERENCES GroupMembers (GroupId, Memberid);
ALTER TABLE MissionRollAssignments
ADD CONSTRAINT fk2 FOREIGN KEY (GroupId, MissionId)
REFERENCES Missions (GroupId, MissionId);
To achieve this SQL Server first requires a (redundant) UNIQUE constraint on (GroupId, MissionId) in the Missions table. Other DBMSs are not so strict but SQL Server requires a FOREIGN KEY constraint to match exactly the columns of a uniqueness constraint.
You should use Foreign Keys to reinforce this, eg Mission.GroupId should refer to Group.GroupId.
Is it possible to enforce referenciay integrity for roll assignments such that only members of the corresponding group (given by the MissionId) are selected?
Yes. You need to use identifying relationships to propagate the GroupId all the way down to the bottom of this "diamond-shaped" dependency, similar to this:
Note FK1 and FK2 in front of MissionRollAssignment.GroupId, indicating that foreign keys exist up the both "sides" of this "diamond-shaped" dependency.
As single active mission can be modeled as a foreign key in the opposite direction, in this case as Group {GroupId, ActiveMissionNo} that references the Mission primary key.
Such circular foreign key presents a "chicken-and-egg" problem on a DBMS that doesn't support deferred constraints (which SQL Server doesn't). However, you can just leave Group.ActiveMissionNo NULL-able, so a DBMS that enforces foreign keys in a MATCH SIMPLE fashion (which SQL Server does) will ignore the whole composite foreign key if just one of its fields is NULL. This will allow you to temporarily "disable" the foreign key and break the "chicken-and-egg" cycle when inserting new data.

Transform Many to Many relation to One to Many relation

I have the following tables (simplified):
create table dbo.Users
(
User_Id int identity not null
constraint PK_Users_Id primary key clustered (Id),
);
create table dbo.UsersSeals
(
UserId int not null,
SealId int not null,
constraint PK_UsersSeals_UserId_SealId primary key clustered (UserId, SealId)
);
create table dbo.Seals
(
Seal_Id int identity not null
constraint PK_Seals_Id primary key clustered (Id),
);
alter table dbo.UsersSeals
add constraint FK_UsersSeals_UserId foreign key (UserId) references Users(Id) on delete cascade on update cascade,
constraint FK_UsersSeals_SealId foreign key (SealId) references Seals(Id) on delete cascade on update cascade;
So I have a MANY to MANY relation between Users and Seals. One user can have many seals and on seal can have many users. I need a ONE to MANY where one user can have many seals but a seal has only one user.
Yes, I could remove the UsersSeals table and add a UserId into Seals table. However, I am using seals, the same way, with other tables.
I would like to have only one Seals tables with One to Many relation with Users tables and other tables.
Can this be done?
Add a separate unique constraint on the UsersSeals table on your SealID column
You then guarantee that this table is unique on SealID, which means that one seal can be associated with only one user but a user can have many seals.