How to implement bidirectional referenced tables? - sql

I have a table School and a table Teacher having a one-to-many relationship. However, one of the teachers is the school's principle, and only one teacher can be the school principle. So I thought of saving the teachers id (principle) in the School table as follows:
CREATE TABLE School (
ID INT PRIMARY KEY,
Name VARCHAR(40),
PrincipleID INT FOREIGN KEY REFERENCES Teacher.ID
)
CREATE TABLE Teacher (
ID INT PRIMARY KEY,
Name VARCHAR(40),
SchoolID INT FOREIGN KEY REFERENCES School.ID
)
I know I could loose the foreign key reference in the school table, but that's not an option.
Should I make the reference after the table creation? If yes, how?

Another solution is to create a new table, let's say SchoolsPrinciples with just two fields:
CREATE TABLE SchoolsPrinciples
(
SchoolId int,
TeacherId int,
CONSTRAINT uc_SchoolTeacher UNIQUE (SchoolId, TeacherId)
)
A UNIQUE constraint let you obtain exactly one teacher per each school.

When building the tables, you'll need to add the constraint as a separate alter statement. Note also that when creating foreign keys, you should only specify the table name, not the referenced column (the column is implied by the primary key).
CREATE TABLE School (
ID INT PRIMARY KEY,
Name VARCHAR(40),
PrincipleID INT);
CREATE TABLE Teacher (
ID INT PRIMARY KEY,
Name VARCHAR(40),
SchoolID INT
CONSTRAINT FK_Teacher_School
FOREIGN KEY REFERENCES School);
ALTER TABLE School add
CONSTRAINT FK_School_Teacher
FOREIGN KEY (PrincipleID) REFERENCES Teacher;
When you add data, you'll need to set the PrincipleID field as a separate update:
insert into School (ID, Name)
values (1, 'Blarg Elementary');
insert into Teacher (ID, Name, SchoolID)
values (1, 'John Doe', 1),
(2, 'Bob Smith', 1),
(3, 'Adam Walker', 1);
update School set PrincipleID = 2 where ID = 1;

Put a boolean IsPrincipal on the Teacher table instead. Or add a third relationship table
CREATE TABLE SchoolPrincipals (
INT SchoolID PRIMARY KEY FOREIGN KEY REFERENCES School.ID,
INT TeacherID FOREIGN KEY REFERENCES Teacher.ID
)
Keeps everything tidy without painful delete logic.

You can take a column in Teacher table as
IsPrincipal where only one row will have value as true as referred
by jonnyGold,
This can be checked by triggers.
OR
You can use filtered index if using Sql Server 2008.
Create unique filtered index where SchoolID, IsPrincipal
is NOT NULL and are unique
Boss where this will contain ID of principal hence creating employee manager relationship which in your case is not suitable.
CREATE TABLE EmpManager
(
TeacherID int
SchoolID int
IsPrincipal bit
)
And use filtered index or trigger to handle the scenario.
EDIT:
CREATE TABLE [dbo].[Teacher](
[ID] [int] NOT NULL primary key,
[Name] [varchar](40) NULL,
[SchoolID] [int] NULL,
)
GO
CREATE TABLE [dbo].[School](
[ID] [int] NOT NULL primary key,
[Name] [varchar](40) NULL,
[PrincipleID] [int] NULL,
)
GO
ALTER TABLE [dbo].[Teacher] WITH CHECK ADD CONSTRAINT [FK_Teacher_School] FOREIGN KEY([SchoolID])
REFERENCES [dbo].[School] ([ID])
GO
ALTER TABLE [dbo].[School] WITH CHECK ADD CONSTRAINT [FK_School_Teacher] FOREIGN KEY([PrincipleID])
REFERENCES [dbo].[Teacher] ([ID])
GO
Better design should be the one suggested by ADC

Related

Prevent multiple foreign key references to same row in primary table

I have a table containing Employees all of whom have an ID; I'm referencing this ID in two other tables (Salesman, Mechanic) via a foreign key. What I want to ensure is that an employee is either a mechanic or a salesman, but never both. In other words, I want to associate this logic with my foreign keys:
How would I integrate logic like that into a table? I'm a SQL beginner, so I apologize if this is a dumb question.
These are my tables:
CREATE TABLE [dbo].[Employee]
(
Number INT NOT NULL,
-- ...
PRIMARY KEY(Number)
);
CREATE TABLE [dbo].[Salesman]
(
ID INT NOT NULL,
-- ...
PRIMARY KEY(ID),
FOREIGN KEY(ID) REFERENCES [dbo].[Employee](ID)
);
CREATE TABLE [dbo].[Mechanic]
(
ID INT NOT NULL,
-- ...
PRIMARY KEY(ID),
FOREIGN KEY(ID) REFERENCES [dbo].[Employee](ID)
);
This is a one-of relationship and it is tricky to implement in SQL. Here is one method:
CREATE TABLE [dbo].[Employee] (
EmployeeId INT PRIMARY KEY,
EmployeeType VARCHAR(32)
-- ...
CHECK (EmployeeType IN ('Mechanic', 'SalesPerson')),
UNIQUE (EmployeeType, EmployeeId)
);
CREATE TABLE [dbo].[SalesPerson]
(
EmployeeId INT PRIMAY KEY,
-- ...
EmployeeType as (CONVERT(VARCHAR(32), 'Salesperson')) PERSISTED,
FOREIGN KEY (EmployeeType, EmployeeId) REFERENCES [dbo].[Employee](EmployeeType, EmployeeId)
);
CREATE TABLE [dbo].[Mechanic] (
EmployeeId INT PRIMARY KEY,
EmployeeType as (CONVERT(VARCHAR(32), 'Mechanic')) PERSISTED,
-- ...
FOREIGN KEY (EmployeeType, EmployeeId) REFERENCES [dbo].[Employee](EmployeeType, EmployeeId)
);
Here is a SQL Fiddle illustrating the code.

Issues with creating SQL Server table relationships

I have 2 tables.
First table:
create table abc
(
AId INT IDENTITY(1,1),
Name NVARCHAR(50),
EMP NVARCHAR(50)
CONSTRAINT PK_abc PRIMARY KEY (AId, Name)
)
And second table as:
create table def
(
AId INT,
Comment NVARCHAR(50)
constraint FK_aid FOREIGN KEY (AId) references abc (AId)
)
This throws an error:
There are no primary or candidate keys in the referenced table 'abc' that match the referencing column list in the foreign key 'FK_aid'.
So I updated as:
create table def
(
AId INT,
Name NVARCHAR(50),
Comment NVARCHAR(50)
constraint FK_AID FOREIGN KEY (AId, Name) references abc (AId, Name)
)
But this throws another error:
More than one key specified in column level FOREIGN KEY constraint, table 'def'.
Not sure what am I missing here.
---Updated----
Sorry for giving vague example. I was having difficulty in explaining my problem here. I have attached the screenshot of my problem. This show the eventual output that I am expecting by making join to 3 tables. Where the data of 3 tables is populated from an input form.
I have tried to provide in a clear way. Let me know if you need more inputs.
Attchment at:
https://imgur.com/a/jfFS6
Thanks
You have an identity column. Use it as the primary key:
create table abc (
AId INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(50),
EMP NVARCHAR(50)
);
create table def (
AId INT,
Comment NVARCHAR(50)
constraint FK_aid FOREIGN KEY (AId) references abc (AId)
);
Name should not be in the definition of the primary key.
Looks like you have to do it as a separate statement:
ALTER TABLE [dbo].[def] WITH CHECK ADD CONSTRAINT [FK_def_abc] FOREIGN KEY([AId], [Name])
REFERENCES [dbo].[abc] ([AId], [Name])
GO
ALTER TABLE [dbo].[def] CHECK CONSTRAINT [FK_def_abc]
GO
But you still should NOT do that. Identity is unique and it alone should be used as primary key.

Foreign key in the first table

I have a question about foreign keys.
How does it work when I want to add a foreign key to the first table that I make that references to the primary key of the second table I create?
CREATE TABLE table1
(
name_id INT NOT NULL,
team TEXT REFERENCES table2(team_id),
PRIMARY KEY(name_id)
);
CREATE TABLE table2
(
team_id INT NOT NULL,
teamname TEXT,
PRIMARY KEY(team_id)
);
If I try the code above I get the following error:
ERROR: relation "" does not exist
Thanks in advance.
Either create the second table first. Or use alter table. That is, create the first table without the reference and then do:
alter table table1 add constraint fk_table1_team
foreign key (team_id) REFERENCES table2(team_id);
The declaration for table1 would be:
CREATE TABLE table1 (
name_id INT NOT NULL,
team_id INT,
PRIMARY KEY(name_id)
);
The reference between the tables should be on the primary key and certainly not on a character column, if an integer is available.
here's the syntax of creating a table with Foreign key:
CREATE TABLE table11
(
name_id INT NOT NULL,
team INT,
PRIMARY KEY(name_id),
foreign key(team) references table22(team_id)
);
CREATE TABLE table22
(
team_id INT NOT NULL,
teamname TEXT,
PRIMARY KEY(team_id)
);
but there was another problem. a foreign key from a child table cannot reference to a primary key from a parent folder if they do not contain the same type. in your code team was of TEXT and team_id was of INT which cannot be.

how to delete relationship between two tables?

I created two tables How to delete relationship between them in sql code;
Course table:
create table course
(
course_id int primary key identity (1,1),
course_name varchar(40)
);
Employee table:
create table employee
(
emp_id int identity(1,1) primary key,
fname varchar(30),
course_id int
foreign key references course (course_id)
);
If this is for SQL Server - then you can find out the name of the FK constraint using this statement:
SELECT name
FROM sys.foreign_keys
WHERE parent_object_id = OBJECT_ID('employee')
AND referenced_object_id = OBJECT_ID('course')
and once you have that FK constraint name, you can use the usual
ALTER TABLE dbo.employee DROP CONSTRAINT (name of the FK constraint)
This will be an arbitrary, system-generated name (something like FK__employee__cours__7EB7AD3A or similar) - and this is the reason I'd recommend to always explicitly name your constraints - like this:
create table employee
(
emp_id int identity(1,1) primary key,
fname varchar(30),
course_id int
constraint fk_employee_course
foreign key references course (course_id)
);
Now, you know what the name of that FK constraint is - you named it fk_employee_course. This is also beneficial if you get any error messages about FK constraint violations - if that name is intuitive and obvious, then you'll know what went wrong

SQL Management Studio 2012 Foreign Key Is A Mess

I am trying to add a foreign key to a table. I have created two tables.
CREATE TABLE madeupbusiness.staff
(
staffnum int NOT NULL,
forename varchar(30) NOT NULL,
surname varchar(30) NOT NULL,
meeting int NOT NULL,
PRIMARY KEY (staffnum),
)
GO
meeting should use the PK from from the meeting table to create a FK :
CREATE TABLE madeupbusiness.meeting
(
meetingnum int NOT NULL,
room varchar(30) NOT NULL,
PRIMARY KEY (meetingnum),
)
GO
To create the foreign key I run this query
ALTER TABLE madeupbusiness.staff
WITH CHECK
ADD CONSTRAINT FK_staff_meetingnum FOREIGN KEY (meetingnum)
REFERENCES madeupbusiness.meeting(meetingnum)
ON DELETE CASCADE
ON UPDATE CASCADE
;
GO
The query runs but when I create a database diagram there is a square loop the staff table from the staffnum key back onto it. Sorry but I don't really know how to describe it. There is no relationship between the two tables. What am I doing wrong?
I have tried to add the relationship from design view but the foreign key table is greyed out.
If you can rebuild the Table do this:
CREATE TABLE madeupbusiness.meeting
(meetingnum int NOT NULL PRIMARY KEY REFERENCES madeupbusiness.meeting(YourColumnYouWantItShouldBeReferenced),
room varchar(30) NOT NULL);
GO