One-One relationship constraint - database

i actually want to implement a compulsory one-one relationship between two tables from my ERD in Oracle. The two tables are Governor and State. A governor can govern only one state and a state must have one and only one governor. I want to implement that in Oracle. I have written the queries as follows
create table gov
(gid number(3) ,name varchar2(100),
constraint gov_pk primary key (gid)
);
create table state
(
sid number(3) ,
name varchar2(100),
gid number(3),
constraint state_pk primary key (sid),
constraint gov_state_fk foreign key (gid) references gov(gid),
constraint state_uk unique(gid,name)
);
But that does not seem to work. I could not find any alternative way. Please help me with this. I will be thankful to you. And please let me know why is is failing to establish one-one relationship.

You're pretty close to successfully implementing your requirements.
" a state must have one and only one governer"
So make GID mandatory on STATE table.
"A governer can govern only one state "
So enforce a unique key on just GID.
create table state
(
sid number(3) ,
name varchar2(100),
gid number(3) not null,
constraint state_pk primary key (sid),
constraint gov_state_fk foreign key (gid) references gov(gid),
constraint state_uk unique(gid)
);
"I can successfully add data to gov table with out adding any row in state table."
Enforcing a Parent must have a Child relationship is pretty hard.
SQL standards have the concept of Assertions, which could enforce that kind of business rule, but Oracle (nor any other DBMS vendor) have not implemented them.
a foreign key on GOV referencing STATE is right out, because circular dependencies are deadly.
that leaves us with a trigger on GOV.
Here is such a trigger:
create or replace trigger enforce_gov_state
before insert or update on gov
for each row
is
l_sid state.sid%type;
begin
select s.sid into l_sid
from state s
where s.gid = :new.gid;
exception
when no_data_found then
raise_application_error(-20000, 'Governor must have a state');
end;
/
So that's okay then. Just one little wrinkle: how do we insert rows into either table???? We can't insert into GOV until the state exists; we can't insert into STATE until the governor exists.
There is a workaround: defer the foreign key on STATE so it's not enforced until the whole transaction is committed. This permits the creation of STATE record followed by GOV record. Of course, we need to know the value of STATE.GID before we create the GOV record.
Also, there are similar snags attached to changing the GOV - STATE relationship. Except that it can be solved by updating all the GOV attributes (except GID) to fit a new Governor. Which is kind of sketchy but there you go.
Why does Oracle make this so hard? Often a one-to-one relationship between tables which is mandatory on both sides points to a flawed data model.
Sometimes 1:1 points to a single table. That is unsatisfactory when
we have two distinct entities such as here.
More likely the 1:1
relationship is wrong, and it's actually 1:N or even M:N. Consider
that a State can have many Governors, one current, many previous and
optionally one elect. Likewise a politician can theoretically be
Governor of more than one state over the course of a career.
So a more truthful implementation would have STATE_GOV as an intersection table between STATE and GOV. It is much simpler to maintain such a table, which is a good sign.

Remove FK from state table. Having it and making it unique means you can't enter a state without already knowing the governor. Create an intersection table between State and Gov with a unique constraint on each FK:
create table StateGov(
StateID number( 3 ) not null references State( sid ),
GovID number( 3 ) not null references Gov( gid ),
constraint UQ_StateGov_State unique StateID,
constraint UQ_StateGov_Gov unique GovID
);
No state can appear more than once, no governor can appear more than once. No circular references, no assertions, no problem with inserting a state record before you know the governor.

Add a unique constraint to STATE:
create table state
(
sid number(3) ,
name varchar2(100),
gid number(3),
constraint state_pk primary key (sid),
constraint gov_state_fk foreign key (gid) references gov(gid),
constraint state_uk unique(gid,name)
constraint gov_state_uk unique (gid)
);

Related

Primary key column with Foreign key reference to itself

I came across this T-SQL code in a client's database today:
CREATE TABLE dbo.Dates
(
MarketDate date,
PRIMARY KEY (MarketDate),
FOREIGN KEY (MarketDate) REFERENCES dbo.Dates (MarketDate)
)
It is unclear to me what purpose can be served by allowing the primary key column to have a foreign key relationship back to itself. Naturally I have deleted the relationship.
Would this foreign key have any effect at all? Is there ever a use case which would justify using it? If not then why would SQL Server permit such a relationship.
The only reason I can imagine is that the creator of the table wanted to disallow the use of TRUNCATE TABLE statements against the Dates table.

SQL Server: Unable to create relationship

I was trying to create a table that has a one to many relationships. but it seems that adding a foreign key in Personal is not working. I am trying to link a Personal Information table to a address table? what is the solution for this error?
Address table saved successfully
Personal table
Unable to create relationship 'FK_Personal_Address'.
Cascading foreign key 'FK_Personal_Address' cannot be created where the
referencing column 'Personal.ID' is an identity column. Could not
create constraint. See previous errors.
The primary key in the Person table is presumably an identity. This is an auto-incrementing integer field.
You need to make the foreign key in the address table of type int, not identity. It will hold integers which correspond to Person records, but you don't want the foreign key to auto-increment. For each record in the child table (address) you will set a specific value for the foreign key indicating to which parent record (Person) it belongs.
Example:
INSERT person (firstname, lastname) VALUES ('John', 'Smith')
This will insert the new person record and the field personid will be filled automatically because it is an IDENTITYfield.
Now to insert an address from John Smith you need to know his personid. For example:
-- Say, for example, personid of John Smith is 55
INSERT address (personid, street, city) VALUES (55, 'High Street', 'London')
So in the person table the personid is generated automatically but in the address table you specify the value that matches an existing person. That's the whole point of a foreign key.
Without more information about your schema it's hard to guess the problem.
I made sure to follow identity, int and primary key discussed in above answer. However, I was still getting the same error.
'xReason' table saved successfully
'xAddress' table
- Unable to create relationship 'FK_xAddress_xReason'.
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_xAddress_xReason". The conflict occurred in database "databaseName", table "dbo.xReason", column 'xReasonID'.
This error resolved when I inserted some data into a Reason table. (table that had a primary key)
If you read this far, this might be your problem.
Without seeing the structure of the tables in the question, I believe the most likely cause is the column in your child table (Address) is marked as an Identity column. In a foreign-key relationship, the parent determines the value of the field, not the child. The column may be the PK in the child table, but not an Identity.
it seem that you try to create a foreign key on Personal.ID related to itself.
You probably want to do something like :
ALTER TABLE Adress WITH NOCHECK ADD CONSTRAINT [FK_Adress_Personnal] FOREIGN KEY(Personal_Id)
REFERENCES Personal (ID)
I got the same error with adding foreign key constraints to one of my tables.
I found the workaround was to add it WITH NOCHECK. why I was able to add the other two foreign keys WITH CHECK but not the third foreign? I found that it was not the table but the order of the foreign key to be added. Any insight to this will be much appreciated.

Missing FK Relationship in Entity Framework Model

I had a lot of trouble implementing the technique described in an Alexander Kuznetsov article. Basically, the article describes a way to create a FK between one table and alternate tables, and still maintain full constraints on those relationship.
Here's part of Alexander's code:
CREATE TABLE dbo.Vehicles(
ID INT NOT NULL,
[Type] VARCHAR(5) NOT NULL,
CONSTRAINT Vehicles_PK PRIMARY KEY(ID),
CONSTRAINT Vehicles_UNQ_ID_Type UNIQUE(ID, [Type]),
CONSTRAINT Vehicles_CHK_ValidTypes CHECK([Type] IN ('Car', 'Truck'))
)
CREATE TABLE dbo.Cars(ID INT NOT NULL,
[Type] AS CAST('Car' AS VARCHAR(5)) PERSISTED,
OtherData VARCHAR(10) NULL,
CONSTRAINT Cars_PK PRIMARY KEY(ID),
CONSTRAINT Cars_FK_Vehicles FOREIGN KEY(ID, [Type])
REFERENCES dbo.Vehicles(ID, [Type])
)
I finally got it working after errors and confirmed bugs. But when I generate my EF models from the new schema, it is missing a relationship between two of my tables.
The problem is that, in order to have a FK on two columns, there must be an index or unique constraint on both those columns. However, in my case, I also have another table with a FK to a single column in the base table (Vehicles, in Alexander's code).
Since you cannot have more than one PK in a table, this means I cannot have a FK to a PK on both sides. The PK can be for one or two columns, and the other FK will need to reference the non-PK unique constraint.
Unfortunately, Entity Framework will only create relationships for you when there is a FK to a PK. That's the problem. Can someone who understand DB design better than I spot any other alternatives here?
Note: I realize some will see the obvious fix as simply modifying the model to manually add the additional relationship. Unfortunately, we are using a database project and are constantly using automated systems to regenerate the project and model from an updated database. So manual steps are really not practical.
You can't have more than one PK, but you can have more than one unique constraint, and in SQL Server you can create a foreign key constraint that references a unique constraint (one or multiple columns). Here is an example of two tables that roughly look like your model.
CREATE TABLE dbo.Vehicles
(
VehicleID INT PRIMARY KEY,
[Type] VARCHAR(5) NOT NULL UNIQUE,
CONSTRAINT u1 UNIQUE(VehicleID, [Type])
);
CREATE TABLE dbo.Cars
(
CarID INT PRIMARY KEY,
VehicleID INT NOT NULL
FOREIGN KEY REFERENCES dbo.Vehicles(VehicleID),
[Type] VARCHAR(5) NOT NULL
FOREIGN KEY REFERENCES dbo.Vehicles([Type]),
CONSTRAINT fk1 FOREIGN KEY (VehicleID, [Type])
REFERENCES dbo.Vehicles(VehicleID, [Type])
);
Note that Cars has three foreign keys: one points to the PK of vehicles (VehicleID), one points to the unique constraint on Vehicles([Type]), and one points to the multi-column unique constraint on Vehicles(VehicleID, [Type]). I realize this is not equivalent to what you are trying to do but should demonstrate that SQL Server, at least, is capable of doing everything you seem to want to do (I'm having a hard time concluding what you're actually because you keep swapping concepts between what Alex did, what you're trying to do but failing, and what you've done successfully).
Are you saying that EF will not recognize a foreign key that references a unique constraint? If so, does that affect constraints that have more than one column, or all unique constraints? If this is the case, that's a shame, because it is certainly supported in SQL Server. Seems like this would either be a bug or an intentional omission (given that the standard doesn't strictly allow FKs against unique constraints). I wonder if there are any bugs reported on Connect?
I have no idea how to force EF to recognize it, but I do know that just about all the people I know who use database projects end up performing pre- or post-deployment modifications and these can be relatively automated.

Bidirectional foreign key constraint

I'm thinking of designing a database schema similar to the following:
Person (
PersonID int primary key,
PrimaryAddressID int not null,
...
)
Address (
AddressID int primary key,
PersonID int not null,
...
)
Person.PrimaryAddressID and Address.PersonID would be foreign keys to the corresponding tables.
The obvious problem is that it's impossible to insert anything into either table. Is there any way to design a working schema that enforces every Person having a primary address?
"I believe this is impossible. You cannot create an Address Record until you know the ID of the person and you cannot insert the person record until you know an AddressId for the PrimaryAddressId field."
On the face of it, that claim seems SO appealing. However, it is quite propostrous.
This is a very common kind of problem that the SQL DBMS vendors have been trying to attack for perhaps decades already.
The key is that all constraint checking must be "deferred" until both inserts are done. That can be achieved under different forms. Database transactions may offer the possibility to do something like "SET deferred constraint checking ON", and you're done (were it not for the fact that in this particular example, you'd likely have to mess very hard with your design in order to be able to just DEFINE the two FK constraints, because one of them simply ISN'T a 'true' FK in the SQL sense !).
Trigger-based solutions as described here achieve essentially the same effect, but those are exposed to all the maintenance problems that exist with application-enforced integrity.
In their work, Chris Date & Hugh Darwen describe what is imo the true solution to the problem : multiple assignment. That is, essentially, the possibility to compose several distinct update statements and have the DBMS act upon it as if that were one single statement. Implementations of that concept do exist, but you won't find any that talks SQL.
This is a perfect example of many-to-many relationship. To resolve that you should have intermediate PERSON_ADDRESS table. In other words;
PERSON table
person_id (PK)
ADDRESS table
address_id (PK)
PERSON_ADDRESS
person_id (FK) <= PERSON
address_id (FK) <= ADDRESS
is_primary (BOOLEAN - Y/N)
This way you can assign multiple addresses to a PERSON and also reuse ADDRESS records in multiple PERSONs (for family members, employees of the same company etc.). Using is_primary field in PERSON_ADDRESS table, you can identify if that person_addrees combination is a primary address for a person.
We mark the primary address in our address table and then have triggers that enforces only record per person can have it (but one record must have it). If you change the primary address, it will update the old primary address as well as the new one. If you delete a primary address and other addresses exist, it will promote one of them (basesd ona series of rules) to the primary address. If the address is inserted and is the first address inserted, it will mark that one automatically as the primary address.
The second FK (PersonId from Address to Person) is too restrictive, IMHO. Are you suggesting that one address can only have a single person?
From your design, it seems that an address can apply to only one person, so just use the PersonID as the key to the address table, and drop the AddressID key field.
I know I'll probably be crucified or whatever, but here goes...
I've done it like this for my "particular very own unique and non-standard" business need ( =( God I'm starting to sound like SQL DDL even when I speak).
Here's an exaxmple:
CREATE TABLE IF NOT EXISTS PERSON(
ID INT,
CONSTRAINT PRIMARY KEY (ID),
ADDRESS_ID INT NOT NULL DEFAULT 1,
DESCRIPTION VARCHAR(255),
CONSTRAINT PERSON_UQ UNIQUE KEY (ADDRESS_ID, ...));
INSERT INTO PERSON(ID, DESCRIPTION)
VALUES (1, 'GOVERNMENT');
CREATE TABLE IF NOT EXISTS ADDRESS(
ID INT,
CONSTRAINT PRIMARY KEY (ID),
PERSON_ID INT NOT NULL DEFAULT 1,
DESCRIPTION VARCHAR(255),
CONSTRAINT ADDRESS_UQ UNIQUE KEY (PERSON_ID, ...),
CONSTRAINT ADDRESS_PERSON_FK FOREIGN KEY (PERSON_ID) REFERENCES PERSON(ID));
INSERT INTO ADDRESS(ID, DESCRIPTION)
VALUES (1, 'ABANDONED HOUSE AT THIS ADDRESS');
ALTER TABLE PERSON ADD CONSTRAINT PERSON_ADDRESS_FK FOREIGN KEY (ADDRESS_ID) REFERENCES ADDRESS(ID);
<...life goes on... whether you provide and address or not to the person and vice versa>
I defined one table, then the other table referencing the first and then altered the first to reflect the reference to the second (which didn't exist at the time of the first table's creation). It's not meant for a particular database; if I need it I just try it and if it works then I use it, if not then I try to avoid having that need in the design (I can't always control that, sometimes the design is handed to me as-is). if you have an address without a person then it belongs to the "government" person. If you have a "homeless person" then it gets the "abandoned house" address. I run a process to determine which houses have no users

Introducing FOREIGN KEY constraint 'c_name' on table 't_name' may cause cycles or multiple cascade paths

I have a database table called Lesson:
columns: [LessonID, LessonNumber, Description] ...plus some other columns
I have another table called Lesson_ScoreBasedSelection:
columns: [LessonID,NextLessonID_1,NextLessonID_2,NextLessonID_3]
When a lesson is completed, its LessonID is looked up in the Lesson_ScoreBasedSelection table to get the three possible next lessons, each of which are associated with a particular range of scores. If the score was 0-33, the LessonID stored in NextLessonID_1 would be used. If the score was 34-66, the LessonID stored in NextLessonID_2 would be used, and so on.
I want to constrain all the columns in the Lesson_ScoreBasedSelection table with foreign keys referencing the LessonID column in the lesson table, since every value in the Lesson_ScoreBasedSelection table must have an entry in the LessonID column of the Lesson table. I also want cascade updates turned on, so that if a LessonID changes in the Lesson table, all references to it in the Lesson_ScoreBasedSelection table get updated.
This particular cascade update seems like a very straightforward, one-way update, but when I try to apply a foreign key constraint to each field in the Lesson_ScoreBasedSelection table referencing the LessonID field in the Lesson table, I get the error:
Introducing FOREIGN KEY constraint 'c_name' on table 'Lesson_ScoreBasedSelection' may cause cycles or multiple cascade paths.
Can anyone explain why I'm getting this error or how I can achieve the constraints and cascading updating I described?
You can't have more than one cascading RI link to a single table in any given linked table. Microsoft explains this:
You receive this error message because
in SQL Server, a table cannot appear
more than one time in a list of all
the cascading referential actions that
are started by either a DELETE or an
UPDATE statement. For example, the
tree of cascading referential actions
must only have one path to a
particular table on the cascading
referential actions tree.
Given the SQL Server constraint on this, why don't you solve this problem by creating a table with SelectionID (PK), LessonID, Next_LessonID, QualifyingScore as the columns. Use a constraint to ensure LessonID and QualifyingScore are unique.
In the QualifyingScore column, I'd use a tinyint, and make it 0, 1, or 2. That, or you could do a QualifyingMinScore and QualifyingMaxScore column so you could say,
SELECT * FROM NextLesson
WHERE LessonID = #MyLesson
AND QualifyingMinScore <= #MyScore
AND #MyScore <= QualifyingMaxScore
Cheers,
Eric

Resources