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?
Related
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.
I have the following T-SQL in VS2013:
CREATE TABLE [dbo].[Jugo]
(
[JugoID] INT IDENTITY (1, 1) NOT NULL,
[Jugo] NVARCHAR (50) NOT NULL,
[ColorID] INT NOT NULL,
[IngreID] INT NOT NULL,
PRIMARY KEY CLUSTERED ([JugoID] ASC),
FOREIGN KEY (ColorID) REFERENCES Color (ColorID)
ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (IngreID) REFERENCES Ingrediente (IngreID)
ON UPDATE CASCADE ON DELETE CASCADE
);
And I get the following message before updating the database:
Highlights
None
User actions
Create
Foreign Key: unnamed constraint on [dbo].[Jugo] (Foreign Key)
Foreign Key: unnamed constraint on [dbo].[Jugo] (Foreign Key)
Supporting actions
None
Can I proceed with these unnamed constraints? What would I need the constraints for?
For reference this is what I'm trying to do:
3 tables:
Jugo, Color, Ingrediente: so to create a jugo (juice) you specify name, color and ingredients, color and ingredients are on their own tables, hence the foreign keys I want to define.
Thanks.
As long as the ColorID and IngreID are both primary key in their own tables, you won't have any trouble.
But here's the catch, you didn't constrain your primary keys. It is a good practice to use constraint for every PRIMARY KEY you are using, in that way, when you foreign key it to another table. It can read that it is from another table. I don't know about SQL in VS2013 But here's my sample for SQL Server:
CREATE TABLE JUGO
(
JUGOID numeric identity (1,1) //For auto increment
CONSTRAINT PK_JUGOID PRIMARY KEY (JUGOID),
JUGO nvarchar(50) not null,
.
.
.
)
The PK_JUGOID in CONSTRAINT PK_JUGOID PRIMARY KEY (JUGOID), is user-defined, but it is a good practice to just copy the format of the primary key so you won't be confused when using foreign keys. :)
Foreign keys are for data consistency. You create the foreign keys on columns, so as not to allow invalid entries.
FOREIGN KEY (ColorID) REFERENCES Color (ColorID)
ON UPDATE CASCADE ON DELETE CASCADE,
This constraint makes sure that your jugo can only have a color that exists in the color table. Moreover you have two cascade commands:
ON UPDATE CASCADE means that if color red is ID 5, but you want to change it to 500, the change will be performed automatically for all jugo records. However, an ID should never change, so this is a clause seldom used.
ON DELETE CASCADE means that if you delete red, then you delete all red jugo records with it. I don't know if this is an appropriate case for you. It is used for instance on a users table. Remove a user, so you remove its complete data. But remove a color?
At last you should give your constraints names, so it's easier for you to deal with them.
CONSTRAINT pk_jugo PRIMARY KEY CLUSTERED ([JugoID] ASC),
CONSTRAINT fk_jugo_color FOREIGN KEY (ColorID) REFERENCES Color (ColorID),
CONSTRAINT fk_jugo_ingre FOREIGN KEY (IngreID) REFERENCES Ingrediente (IngreID)
I am currently making a database back end system on an airport, using sql through the phpmyadmin server. The criteria is not meant to be perfect but one of the ideas behind the queries is to imagine that either a customer or flight dispatch officer might be looking at the tables. I was wondering if it was possible to reference a primary key as a foreign key across 2 or more tables. In the example below, I want to reference the model number as a foreign key in the bottom 2 tables. I have ensured that the type and character count are the same.
CREATE TABLE Aircraft_Model
(Model_Number varchar (12) NOT NULL,
seat_capacity int (3),
CONSTRAINT pk7 primary key (Model_Number));
CREATE TABLE Licence_type
(Rank varchar (25) NOT NULL,
Model_Number varchar (12),
CONSTRAINT pk9 primary key (Rank));
CREATE TABLE Aircraft
(Aircraft_ID varchar (4) NOT NULL,
Model_Number varchar(12),
airport_base text(13),
CONSTRAINT pk1 PRIMARY KEY (Aircraft_ID));
Is this possible? I only want the database to be able to perform about 12-15 simple queries.
Would the syntax of adding a foreign key be something like this?
ALTER TABLE Aircraft
ADD CONSTRAINT fk1 FOREIGN KEY(Model_Number)
REFERENCES Aircraft_Model
Does the same foreign key being referenced from a separate table such as Licence_type need a separate constraint to be added or can it be added from the same one with the same fk1 number?
I was wondering if it was possible to reference a primary key as a
foreign key across 2 or more tables.
If you mean, "Can two or more tables have foreign keys that reference the same column?", then, yes, you can do that. This seems to be what you mean, but it's not what most people mean when they talk about "a foreign key across 2 or more tables".
Declare two different, separate constraints.
ALTER TABLE Aircraft
ADD CONSTRAINT fk1 FOREIGN KEY(Model_Number)
REFERENCES Aircraft_Model (Model_Number);
ALTER TABLE License_Type
ADD CONSTRAINT fk2 FOREIGN KEY(Model_Number)
REFERENCES Aircraft_Model (Model_Number);
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.
So I've got Table ActorInMovies, which has 3 foreign keys.
CREATE TABLE ActorInMovie(
ID_ROLE bigserial REFERENCES Role(ID_ROLE) ON DELETE CASCADE,
ID_ACTOR bigserial REFERENCES Actor(ID_Actor) ON DELETE CASCADE,
ID_MOVIE bigserial REFERENCES Movie(ID_Movie) ON DELETE CASCADE,
CONSTRAINT ActorInMovie_pk PRIMARY KEY (ID_ROLE));
I assumed that when I try to insert something like:
INSERT INTO ActorInMovie (ID_ROLE, ID_ACTOR) values (1,1);
that it would result in an error as ID_MOVIE was not specified (null I supposed).. but it automatically starts assigning indexes staring from 1.
What am I doing wrong? As written here, I thought that "PostgreSQL automatically creates indexes on primary keys and unique constraints, but not on the referencing side of foreign key relationships."
I have a very hard time imagining a use case where a serial(or bigserial) column references another column. It's usually the other way round: the serial column should go on the other end of the foreign key constraint.
I have an equally hard time imagining a design where a movie_id needs to be bigint instead of just int. There aren't nearly enough movies on this planet.
Also, there is a good chance, a column called movie_id in a table called actor_in_movie should be defined as NOT NULL.
In short: I doubt your design flies at all. Maybe something like:
CREATE TABLE actor (actor_id serial PRIMARY KEY, actor text, ...);
CREATE TABLE movie (movie_id serial PRIMARY KEY, movie text, ...);
CREATE TABLE actor_in_movie(
role_id serial PRIMARY KEY
,actor_id int NOT NULL REFERENCES actor(actor_id) ON DELETE CASCADE
,movie_id int NOT NULL REFERENCES movie(movie_id) ON DELETE CASCADE
);
A NOT NULL constraint is redundant, while the column is included in the primary key.
You probably want indices on actor_id and on movie_id in actor_in_movie.
More details:
How to implement a many-to-many relationship in PostgreSQL?
This is simply bigserial working exactly as advertised. It has nothing to do with the foreign key constraint, or with an index.