问题
Just beginning to learn about SQL and had a question I couldn't figure out.
I have a setup based on the following tables and their primary keys, the columns with the same name between tables are constrained by foreign keys:
Company:
- CompanyId
Division:
- CompanyId
- DivisionId
Resource:
- CompanyId
- ResourceId
DivisionResource :
- CompanyId
- DivisionId
- ResourceId
- DivisionResource is used to create a many to many relation between division and resource and constrain them so that divisions can only be linked to resources of the same company.
- Without the DivisionResource, Division and Resource wouldn't need the CompanyId as a primary key to contain unique records.
So my question is this: Is there a way to create a similar constraint as DivisionResource creates without forcing Division and Resource to have an extra column in its primary key?
回答1:
ResourceCompany and DivisionCompany in the schema below are connecting tables. They will have CompanyId in their primary key but Resource and Division will have primary keys with one column. This is what you looked for.
Resource -> ResourceCompany
DivisionResource -> ResourceCompany
Division -> DivisionCompany
DivisionResource -> DivisionCompany
create table Company (CompanyId int primary key);
create table DivisionCompany (
CompanyId int foreign key references Company(CompanyId),
DivisionId int,
constraint pk_div_company primary key (DivisionId, CompanyId)
);
create table Division (
DivisionId int primary key,
CompanyId int,
constraint fk_div_company foreign key (DivisionId, CompanyId) references DivisionCompany(DivisionId, CompanyId));
create table ResourceCompany (
CompanyId int foreign key references Company(CompanyId),
ResourceId int,
constraint pk_res primary key (ResourceId, CompanyId));
create table Resource(
ResourceId int primary key,
CompanyId int,
constraint fk_res_company foreign key (ResourceId, CompanyId) references ResourceCompany(ResourceId, CompanyId)
);
create table DivisionResource(
CompanyId int,
DivisionId int,
ResourceId int,
constraint pk_DivRes primary key (DivisionId, ResourceId),
constraint fk_DivCompany foreign key (DivisionId, CompanyId) references DivisionCompany(DivisionId, CompanyId),
constraint fk_ResCompany foreign key (ResourceId, CompanyId) references ResourceCompany(ResourceId, CompanyId)
);
回答2:
Create INSTEAD OF trigger on insert and update of DivisionResource
The trigger will check if Divistion and Resource have the same company. If they don't, it will fail the modification
Alternatively, it would be even better to have a stored procedure modifying DivisionResource. Then the trigger needs to call it.
回答3:
I'm assuming that you're trying to create the following schema:
CREATE TABLE company (
companyId int PRIMARY KEY)
CREATE TABLE division (
divisionId int PRIMARY KEY,
companyId int
REFERENCES company (companyId) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE TABLE resource (
resourceId int PRIMARY KEY,
companyId int
REFERENCES company (companyId) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE TABLE divisionResource (
divisionId int
REFERENCES division (divisionId) ON DELETE CASCADE ON UPDATE CASCADE,
resourceId int
REFERENCES resource (resourceId) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (divisionId, resourceId))
Which throws:
Introducing FOREIGN KEY constraint on table 'divisionResource' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Changing either divisionId
or resourceId
to ON DELETE NO ACTION ON UPDATE NO ACTION
will essentially break the referential integrity. What I suggested in my comment was to make a surrogate key. However, it would be better if you created a separate table for resource
. This will maintain the referential integrity and also normalize the schema:
CREATE TABLE company (
companyId int PRIMARY KEY)
CREATE TABLE division (
divisionId int PRIMARY KEY,
companyId int
REFERENCES company (companyId) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE TABLE resource (
resourceId int PRIMARY KEY)
CREATE TABLE companyResource (
resourceId int
REFERENCES resource (resourceId) ON DELETE CASCADE ON UPDATE CASCADE,
companyId int
REFERENCES company (companyId) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE TABLE divisionResource (
divisionId int
REFERENCES division (divisionId) ON DELETE CASCADE ON UPDATE CASCADE,
resourceId int
REFERENCES resource (resourceId) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (divisionId, resourceId))
来源:https://stackoverflow.com/questions/14391483/composite-foreign-key-from-multiple-related-tables