Can a relational table have constraints related to another table? If yes, please provide an example also
Yes, think of foreign key constraint. Foreign key constraint is related to another table.
For example, consider following table
Address (Addressid (PK), AddressLine1, City, State_cd (FK))
State (State_cd(PK), State_name)
Note here that State_cd which is in Address table is related to another table (State).
Hope this is clear
Related
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)
);
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.
Trying to write the script to reference a foreign key in another table that is named differently. Here's part of my script, see if you can figure out what im trying to do, I don't know a better way to explain it:
ALTER TABLE journal
ADD CONSTRAINT journal_authorid_FK FOREIGN KEY(author_id) REFERENCES employee.emp_id;
as you can see, the author_id in one table references the emp_id primary key in another table. Reason being is that there is already a key in this table called emp_id.The emp_id FK in this table will be used to identify who this journal entry pertains to. The author_id is the person that made the entry. Obviously they are both located on the employee table. How do I make this relationship?
I believe the syntax is:
ALTER TABLE journal
ADD CONSTRAINT journal_authorid_FK FOREIGN KEY(author_id) REFERENCES employee(emp_id);
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
I have an oracle db which has no Foreign Keys, all table relations are handled by the software. For example, table Customer with columns Customer.customercode, Customer.Name where customercode is the primary key and table Order with columns Order.ordercode (PK), Order.customercode where customercode has no foreign key constraint. So far the application handles all transactions and takes care of all the table relations so that the data are consistent. I need to change this to a proper relational DB implementation, so I need to modify Order.customercode to be a FK from table Customer. Any sqlplus statement to do this without losing my data?
In Oracle, creating a foreign key would never lose any data, but it will fail if the data doesn't correspond to the new constraint. Assuming your data is OK, you can use an alter table statement:
ALTER TABLE order
ADD CONSTRAINT order_customer_fk FOREIGN KEY (customercode)
REFERENCES customer(customercode)