Here is a "natural key" example I did up. Just to show how quickly it can
get out of control.
Basically, I wanted to track.
How many hours an employee worked....during a certain week, on a certain
day. And divide it up by jobtitle.(in case 1 person has more than 1
jobtitle)
(
Example: Mary, during the second week of the year, on Monday.... worked 2
hours as a Manager and 6 hours as a Typist.
John, during the third week of the year, on Friday.... worked 8 hours as a
Developer.
)
(Basically, a time tracker for employees)
Anyway. Needless to say this is just a demo.....and shows how composite
keys when propogated "down the chain" as FK's gets really, really messy.
/*
Use [master]
G-O
DROP Database NaturalKeyDemo
G-O
Create Database NaturalKeyDemo
G-O
*/
Use [NaturalKeyDemo]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[WorkDay]') AND type in (N'U'))
DROP TABLE [dbo].[WorkDay]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].WorkWeek') AND type in (N'U'))
DROP TABLE [dbo].WorkWeek
GO
if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[EmployeeJobTitleLink]') and OBJECTPROPERTY(id,
N'IsUserTable') = 1)
BEGIN
DROP TABLE [dbo].[EmployeeJobTitleLink]
END
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[JobTitle]') AND type in (N'U'))
DROP TABLE [dbo].[JobTitle]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[Employee]') AND type in (N'U'))
DROP TABLE [dbo].[Employee]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[Department]') AND type in (N'U'))
DROP TABLE [dbo].[Department]
GO
CREATE TABLE dbo.Department (
DepartmentID int not null primary key clustered ,
DepartmentName varchar(24) not null unique
)
CREATE TABLE dbo.Employee (
[EmployeeID] int not null primary key clustered ,
DepartmentID [int] NOT NULL FOREIGN KEY (DepartmentID) REFERENCES
dbo.Department(DepartmentID),
LastName varchar(24) not null ,
FirstName varchar(24) not null,
CreateDate [smalldatetime] NOT NULL DEFAULT (getdate()),
HireDate smalldatetime not null ,
)
CREATE TABLE dbo.JobTitle (
JobTitleID int not null primary key clustered ,
JobTitleName varchar(24) not null unique
)
if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[EmployeeJobTitleLink]') and OBJECTPROPERTY(id,
N'IsUserTable') = 1)
BEGIN
DROP TABLE [dbo].[EmployeeJobTitleLink]
END
GO
CREATE TABLE [dbo].[EmployeeJobTitleLink] (
EmployeeID int not null FOREIGN KEY ([EmployeeID]) REFERENCES
dbo.[Employee]([EmployeeID]),
JobTitleID int not null ,
CONSTRAINT Emp_JT_Link_UNIQUE UNIQUE (EmployeeID , JobTitleID)
)
GO
ALTER TABLE dbo.[EmployeeJobTitleLink]
ADD CONSTRAINT EmployeeJobTitleLinkToJobTitleFK
FOREIGN KEY ( JobTitleID )
REFERENCES dbo.JobTitle ( JobTitleID )
ON UPDATE CASCADE
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[WorkWeek]') AND type in (N'U'))
DROP TABLE [dbo].[WorkWeek]
GO
CREATE TABLE [dbo].[WorkWeek]
(
--[WorkWeekID] [uniqueidentifier] NOT NULL DEFAULT newsequentialid() ,
[EmployeeID] int NOT NULL ,
JobTitleID int not null ,
YearOf int not null ,
WeekNumber int not null ,
--HoursWorked int not null default 0 ,
[CreatedDate] [datetime] NOT NULL DEFAULT getdate()
--CONSTRAINT [PKC_WorkWeek_WorkWeekUUID] PRIMARY KEY CLUSTERED (
[WorkWeekUUID] ASC )
)
GO
ALTER TABLE dbo.WorkWeek
ADD CONSTRAINT PK_WorkWeek_Composite
PRIMARY KEY CLUSTERED (EmployeeID, JobTitleID , YearOf , WeekNumber)
GO
ALTER TABLE dbo.WorkWeek
ADD CONSTRAINT WorkWeekToEmployeeJobTitleLinkFK
FOREIGN KEY (EmployeeID, JobTitleID)
REFERENCES dbo.[EmployeeJobTitleLink] (EmployeeID, JobTitleID)
ON UPDATE CASCADE
set nocount on
Insert into dbo.Department ( DepartmentID , DepartmentName)
values (101 , 'Dept101')
Insert into dbo.Department ( DepartmentID , DepartmentName)
values (102 , 'Dept102')
Insert Into dbo.Employee ( EmployeeID , DepartmentID , LastName , FirstName
, HireDate )
values ( 1001 , 101 , 'LN_1001' , 'FN_1001', getdate() )
Insert Into dbo.Employee ( EmployeeID , DepartmentID , LastName , FirstName
, HireDate )
values ( 1002 , 101 , 'LN_1002' , 'FN_1002', getdate() )
Insert Into dbo.Employee ( EmployeeID , DepartmentID , LastName , FirstName
, HireDate )
values ( 1011 , 102 , 'LN_1011' , 'FN_1011', getdate() )
Insert Into dbo.Employee ( EmployeeID , DepartmentID , LastName , FirstName
, HireDate )
values ( 1012 , 102 , 'LN_1012' , 'FN_1012', getdate() )
Insert into dbo.JobTitle ( JobTitleID , JobTitleName )
values (501 , 'Receptionist')
Insert into dbo.JobTitle ( JobTitleID , JobTitleName)
values (502 , 'Janitor')
Insert into dbo.JobTitle ( JobTitleID , JobTitleName)
values (503 , 'HelpDeskWorker')
Insert into dbo.JobTitle ( JobTitleID , JobTitleName)
values (504 , 'SecurityGuard')
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1001 , 501 )
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1001 , 502 )
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1002 , 502 )
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1002 , 503 )
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1011 , 503 )
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1011 , 504 )
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1012 , 501 )
INSERT INTO [dbo].[EmployeeJobTitleLink] ( EmployeeID , JobTitleID )
values ( 1012 , 504 )
INSERT INTO [dbo].[WorkWeek] ( [EmployeeID] , JobTitleID , YearOf ,
WeekNumber )--, HoursWorked )
values ( 1001 , 501 , 2007 , 50 )--, 31 )
INSERT INTO [dbo].[WorkWeek] ( [EmployeeID] , JobTitleID , YearOf ,
WeekNumber )--, HoursWorked )
values ( 1001 , 502 , 2007 , 51 )--, 32 )
select * from dbo.[WorkWeek]
Update [EmployeeJobTitleLink] Set JobTitleID = 504 where EmployeeID = 1001
and JobTitleID = 501
select * from dbo.[WorkWeek]
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[WorkDay]') AND type in (N'U'))
DROP TABLE [dbo].[WorkDay]
GO
CREATE TABLE [dbo].[WorkDay]
(
-- Start FK "Copy"
EmployeeIDCopy int NOT NULL ,
JobTitleIDCopy int not null ,
YearOfCopy int not null ,
WeekNumberCopy int not null ,
WeekDayNumber int not null , --Represents Sunday thru Saturday
DayHoursWorked int not null default 0 ,
)
GO
ALTER TABLE dbo.WorkDay
ADD CONSTRAINT PK_WorkDay_Composite
PRIMARY KEY CLUSTERED (EmployeeIDCopy, JobTitleIDCopy , YearOfCopy ,
WeekNumberCopy , WeekDayNumber , DayHoursWorked )
GO
ALTER TABLE dbo.WorkDay
ADD CONSTRAINT WorkDayToWorkWeekFK
FOREIGN KEY (EmployeeIDCopy , JobTitleIDCopy , YearOfCopy , WeekNumberCopy )
REFERENCES dbo.WorkWeek (EmployeeID, JobTitleID , YearOf , WeekNumber )
ON UPDATE CASCADE
INSERT INTO [dbo].WorkDay ( [EmployeeIDCopy] , JobTitleIDCopy , YearOfCopy ,
WeekNumberCopy , WeekDayNumber , DayHoursWorked )
values ( 1001 , 502 , 2007 , 51 , 2 , 7 )
INSERT INTO [dbo].WorkDay ( [EmployeeIDCopy] , JobTitleIDCopy , YearOfCopy ,
WeekNumberCopy , WeekDayNumber , DayHoursWorked )
values ( 1001 , 502 , 2007 , 51 , 3 , 8 )
INSERT INTO [dbo].WorkDay ( [EmployeeIDCopy] , JobTitleIDCopy , YearOfCopy ,
WeekNumberCopy , WeekDayNumber , DayHoursWorked )
values ( 1001 , 504 , 2007 , 50 , 3 , 7 )
INSERT INTO [dbo].WorkDay ( [EmployeeIDCopy] , JobTitleIDCopy , YearOfCopy ,
WeekNumberCopy , WeekDayNumber , DayHoursWorked )
values ( 1001 , 504 , 2007 , 50 , 4 , 7 )
select * from dbo.WorkDay
Update [EmployeeJobTitleLink] Set JobTitleID = 503 where EmployeeID = 1001
and JobTitleID = 504
select * from dbo.WorkDay
Update JobTitle set JobTitleID = 7777 where JobTitleID = 503
select 0 as Spacer
select * from dbo.JobTitle
select * from dbo.[EmployeeJobTitleLink]
select * from dbo.[WorkWeek]
select * from dbo.WorkDay