Foreign Key Relationship with one of Multiple Tables - sql-server

I have a language map table that each entry has the possibility of a foreign key relationship with a few different tables. What is the best schema to deal with this configuration?
Tables: LanguageMap, TableA, TableB
These are the two possibility:
1. Lookup Column Method - No Foreign Key Constraints:
Create Table LanguageMap (
Id int not null primary key,
Language nvarchar not null,
Value nvarchar not null,
Type nvarchar not null, -- 'TableA', 'TableB', etc.
ForeignTableId int not null -- Is Foreign key to another table dependent on the type of the row.
)
2. Multiple Foreign Key Columns
create Table LanguageMap(
Id int not null primary key,
Language nvarchar not null,
Value nvarchar not null,
Type nvarchar not null, -- 'Activity', 'Verb', etc.
TableAId int null,
TableBId int null
)
alter table LanguageMap add constraint FK_LanguageMap_TableA
foreign key (TableAId) references TableA (Id)
alter table LanguageMap add constraint FK_LanguageMap_TableA
foreign key (TableBId) references TableB (Id)
alter table LanguageMap add constraint CK_LanguageMap_OneIsNotNull
check (TableAId is not null or TableBId is not null)
go
alter table LanguageMap add constraint CK_LanguageMap_OneIsNull
check (TableAId is null or TableBId is null)
go
The foreign key constraints are based on Foreign Key for either-or column?

There is another alternative, called "Shared Primary Key". You can look this up. If TableA, TableB, TableC, etc. all "inherit" their PK as a copy of the PK from some Master table, called "TableMaster" for example, then you can just use that as an FK in LanguageMap.
The correct joins will select the correct instances.
The shared primary key is often used in conjunction with a design pattern called "Class Table Inheritance". Without knowing what TableA, TableB, TableC, etc. are about, I can't say whether Class Table Inheritance is relevant to your case.
In any event, look up both "Shared Primary Key" and "Class Table Inheritance" for further reading.
There are tags with those names in this area.

Related

Entity Framework appears to skip mapping a table with a multi-column primary key set through a constraint

I've created an ADO.NET model via the database first approach.
One of my tables which is listed when creating the model doesn't actually get added to it.
The table has a multi-column primary key, composed of two foreign keys.
CREATE TABLE ForumAccess
(
UserID INT FOREIGN KEY REFERENCES Users(UserID) NOT NULL,
ForumID INT FOREIGN KEY REFERENCES Forums(ForumID) NOT NULL,
CONSTRAINT ForumAccessID PRIMARY KEY (UserID, ForumID),
);
It does show up when I have to select which tables to add, but then it seems to be skipped. No class is generated for it, and it's not shown in the .edmx file.
Part of my application depends on the existence of this table. I have another table which has a multi-column primary key, and another DateTime type column. That table does get added.
That table is:
CREATE TABLE Moderators
(
UserID INT FOREIGN KEY REFERENCES Users(UserID) NOT NULL,
ForumID INT FOREIGN KEY REFERENCES Forums(ForumID) NOT NULL,
TimeOfAddition DateTime NOT NULL, -- When the mod was added as a mod.
CONSTRAINT ModeratorID PRIMARY KEY (UserID, ForumID),
);
Why does the Moderators table get added, but the ForumAccess table doesn't?
There is no error, or any warning that I can see.
What am I missing?

SQL Server : optimize constraint for perform a query bases on 2 columns

I am creating a table Brands with the following schema :
UserId
CarId
Brand
The UserId references the id of an user in the user table
The CarId references the id of a car in the car table
The only query that I will use is a search bases on these 2 columns, to get the corresponding brand.
So my question was about the constraint part, as I am a beginner, I would like to know which type of constraint to use (index, primary key, clustered or non clustered, on each field or on the 2 fields together) to have my query the more optimized possible.
This is my script right now :
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Brands]') AND type in (N'U'))
BEGIN
CREATE TABLE [Brands]
(
UserId BIGINT NOT NULL
CONSTRAINT [FK_Brands_Users]
FOREIGN KEY REFERENCES [Users] (UserId),
CarId BIGINT NOT NULL
CONSTRAINT [FK_Brands_Cars]
FOREIGN KEY REFERENCES [Cars] (CarId),
Brand nvarchar(15),
);
END
GO
ALTER TABLE [Brands]
ADD CONSTRAINT [Unique_UserId_BrandId] UNIQUE(UserId, BrandId);
GO
I would create a primary key including both fields. When you define a primary key it automatically create a clustered index. Also your primary key has a unique constraint build in. Your table is now a heap the way you wrote it here above which is not good. You can additionally create an extra non-clustered index on CarId. Having an additional non-clustered index on UserId is not usefull I think. The column UserId can use the clustered index because it's the first field in the clustered index but I'm not sure about that.

SQL Server foreign relationship on two-column primary key

I have the following three sample tables (simplified demo for purpose of question):
CREATE TABLE Teams
(
Id int IDENTITY(1,1) NOT NULL,
Name varchar(50) NOT NULL,
PRIMARY KEY (Id)
)
CREATE TABLE TeamGroups
(
Id int NOT NULL,
TeamId int NOT NULL,
PRIMARY KEY (Id,TeamId)
)
CREATE TABLE RoomBookings
(
Id int NOT NULL,
TeamGroupId int NOT NULL,
RoomId int NOT NULL,
PRIMARY KEY (Id)
)
and I have the following foreign key already set up:
ALTER TABLE TeamGroups WITH CHECK
ADD CONSTRAINT [FK_TeamGroups_Teams]
FOREIGN KEY (TeamId) REFERENCES Teams(Id)
The idea is that each Team can be in zero or more TeamGroups, and each TeamGroup can have zero or more RoomBookings
To reflect that, I want to add a foreign key from the RoomBookings table into the TeamGroups table.
I tried using the Relationships GUI in Management Studio to create the foreign key (primary key table: TeamGroups.ID, foreign key table: RoomBookings.TeamGroupId) but I get an error:
The columns in table 'TeamGroups' do not match an existing primary key
or UNIQUE constraint
I'm assuming it's because the TeamGroups table has a two-column primary key?
I don't really want to make a foreign key constraint from the TeamGroups table (eg, the key is present in the TeamGroups table), as the table will eventually be used by other tables (such as EquipmentBookings, GroupManagers, etc).
Any help?
If your primary key is made up from more than one columns, then all foregin keys also must have all those columns - there's no way around this.
But I don't understand why you'd get this error trying to link TeamGroups to Team based on the Team.Id column.... that should work just fine.
Try using this:
ALTER TABLE TeamGroups WITH CHECK
ADD CONSTRAINT [FK_TeamGroups_Teams]
FOREIGN KEY (TeamId) REFERENCES Teams(Id);
You had Teams (which is not a valid column in TeamGroups at all), and you had REFERENCES Teams.id which is wrong - it needs to be REFERNCES Teams(Id); (column in parenthesis - not the "dot" notation)
Update: from TeamGroups to RoomBookings - yes.... either use both columns from TeamGroups in your RoomBookings table - or what would stop you from making the TeamGroups.Id column an INT IDENTITY and then have the PK on just this one column?? Any good reason for that??
CREATE TABLE TeamGroups
(
TeamGroupId int NOT NULL,
TeamId int NOT NULL,
PRIMARY KEY (TeamGroupId)
)
ALTER TABLE dbo.RoomBookings
ADD CONSTRAINT FK_RoomBookings_TeamGroup
FOREIGN KEY TeamGroupId REFERENCES TeamGroups(TeamGroupId)

How to create database schema with shared primary foreign key?

My goal is to have a subtable whose primary key and foreign key both are the same column, and reference to an ID of the main table.
CREATE TABLE main_table(
id integer NOT NULL,
//some fields
)
CREATE TABLE test(
id integer NOT NULL,
name varchar,
CONSTRAINT test_pk PRIMARAY KEY (id),
CONSTRAINT test_fk FOREIGN KEY (fk_id)
REFERENCES main_table (id) MATCH SIMPLE
)
But this will create a table mapping with two columns: id[PK] and test_fk as foreign key column. How can I combine them?
You have misunderstood how the foreign key clause works. You list the names of existing columns in there. And listing the column names will create any new column. Any FK column must have already be defined in the "columns part" of the create table statement.
So your statement wouldn't work at all because the table test does not have a column named fk_id. You need to supply the name of the already defined column id there:
CREATE TABLE test(
id integer NOT NULL,
name varchar,
CONSTRAINT test_pk PRIMARAY KEY (id),
CONSTRAINT test_fk FOREIGN KEY (id) --- <<< this was wrong
REFERENCES main_table (id) MATCH SIMPLE
)

Add a unique constraint of a sql table as foreign key reference to an another sql table

how to add a unique constraint of a sql table as foreign key reference to an another sql table in sql server 2005
In order to add FK constraint (in child table to parent table) you have to add unique constraint to parent table columns of relationship.
All the rest is optional or has nothing to do with FK:
no obligatory need of any primary key
no need of uniqueness in child table colums(s)
The parent table (in such FK relation) is frequently called (including by SSMS) as Primary Key table but PK is not must, unique key/constraint in parent table is enough (as PK is unique, it is particular case of unique constraint in parent table).
Drop TableA and TableB from answer by Matt, which is confusing for beginners,
and recreate them as
CREATE TABLE parentB--TableB
(
PK1 INT NOT NULL,
PK2 INT NOT NULL,
--I would not have additional non-referenced data in parent table,
--rather in child table
--SomeData VARCHAR(1000),
--CONSTRAINT PK_TableB PRIMARY KEY CLUSTERED (PK1, PK2)
)
CREATE TABLE childA--TableA
(
--PK INT, -- NOT NULL,
FK1 INT-- NOT NULL, -- Or NULL, if you''d rather.
FK2 INT --NOT NULL --,
, SomeData VARCHAR(1000)
--CONSTRAINT PK_TableA PRIMARY KEY CLUSTERED (PK),
--CONSTRAINT FK_TableA_FK1FK2 FOREIGN KEY (FK1, FK2) REFERENCES TableB (PK1, PK2),
--CONSTRAINT Cons2cols UNIQUE(FK1, FK2)
)
Now, in order, to add FK
ALTER TABLE childA
ADD
--constraint FK1_childA
--this is optional, if one needs to add his own custom name
FOREIGN KEY (FK1) REFERENCES parentB(PK1);
you should first create unique constraint on corresponding referenced column in parent table column:
ALTER TABLE parentB ADD
--CONSTRAINT YourUniqueName --uncomment for adding your own name to constraint
UNIQUE(PK1)
Similarly for 2 columns foreign key constraint
(first, you need corresponding unique constraint in parent table):
ALTER TABLE parentB ADD
--CONSTRAINT YourUniqueName --for adding your own name to unique constraint
UNIQUE(PK1,PK2)
ALTER TABLE childA
ADD
--constraint yourUniqueName --uncomment for adding your own name to FK constraint
FOREIGN KEY (FK1, FK2) REFERENCES parentB(PK1, PK2);
Apologies but I'm not really sure what you're asking here. Giving more of an example with table definitions would help! I think you're saying you have two columns in TableA in a unique constraint named "Cons2cols", and you also want these two columns to be a FK to a two column PK / unqiue pair in TableB.
That works as follows, if you're creating the tables from scratch:
CREATE TABLE TableB (
PK1 INT NOT NULL,
PK2 INT NOT NULL,
SomeData VARCHAR(1000),
CONSTRAINT PK_TableB PRIMARY KEY CLUSTERED (PK1, PK2)
)
CREATE TABLE TableA (
PK INT NOT NULL,
FK1 INT NOT NULL, -- Or NULL, if you''d rather.
FK2 INT NOT NULL,
CONSTRAINT PK_TableA PRIMARY KEY CLUSTERED (PK),
CONSTRAINT FK_TableA_FK1FK2 FOREIGN KEY (FK1, FK2) REFERENCES TableB (PK1, PK2),
CONSTRAINT Cons2cols UNIQUE(FK1, FK2)
)
If the tables already exist, you can add in these same constraints after the fact:
ALTER TABLE TableA ADD CONSTRAINT FK_TableA_FK1FK2 FOREIGN KEY (FK1, FK2) REFERENCES TableB (PK1, PK2);
ALTER TABLE TableA ADD CONSTRAINT Cons2cols UNIQUE(FK1, FK2);
Either way, TableA now has a unique, 2 column FK to another table.
You need to keep in mind that adding a FK on a column does not automatically put an index on that column. You'll need to do this in two steps.
1) Make a column in your table a FK to a parent table.
2) Add a unique constraint on that same column
Forget about the unique constraint for now. Just create your new foreign key on the two columns.
ALTER TABLE dbo.PurchaseDetail
ADD FOREIGN KEY (Customer, Product)
REFERENCES dbo.Purchase (Customer, Product)
I prefer this approach where this table references another table (transaction_log):
CREATE TABLE transaction_settings_log
(
transaction_fk UUID NOT NULL
CONSTRAINT transaction_log_pkey REFERENCES transaction_log (id) UNIQUE,
group_selected BOOLEAN DEFAULT TRUE,
leg_closed BOOLEAN DEFAULT FALSE
);

Resources