create a table with composed primary keys - oracle

I have a table:
course
---------
id_course
id_groupe (references a table named group)
id_module (references a table named module)
In my case a course can be shared by many groups.
My question is :
it is correct to choose the primary key composed of (id_course , id_group )?
and is there any other way to make the same table ?

Lets assume that the course has another attribute - its title.
Ask yourself the question:
Will the title of the course change if it is being taken by a member of "group A" or "group B"?
For most institutions, a course will have a set title and it does not matter who is taking that course so with your table structure you will have to duplicate the title across every course/group combination and breaks the concept of database normalisation.
You would be better splitting the table into two tables:
course
---------
id_course (Primary Key)
title
course_group
------------
id_course (FK referencing course) } composite PK
id_groupe (FK referencing groupe) }
Then you can set the title for the course and it is independent of the groups associated with the course. You can, of course, have a composite primary key on the course_group table consisting of both ids to enforce uniqueness.

If you have a course that may be shared by many groups, I'd think of a sligthly different design, with a relation table linking COURSE and GROUPE; this table could have a composite PK, based on the two foreing key columns:
COURSE
id_course PK
id_module KF references MODULE
MODULE
id_module PK
GROUPE
id_groupe PK
COURSE_REL_GROUPE
id_course FK references COURSE
id_groupe FK references GROUPE
PRIMARY KEY (id__course, id_groupe)

Related

Does a foreign key always refer to a primary key?

I'm a bit confused about this. Must a foreign key always reference a primaryy key? What if there's two foreign key on the same table that refer to the same primary key?
Thanks
"What if there's two foreign key on the same table that refer to the same primary key?
"
Any number of child tables can reference a parent table. There are certain situations in which it is possible for a child table to have more than one foreign key on the same parent.
For instance, any form of sporting contest has opponents of the same type - player, team, etc. So a match will have two instances of that entity, hance the child table will have two columns with foreign keys referencing the same primary key.
create table player (
player_id number not null primary key
, name varchar2(30) not null unique
);
create table match (
match_id number not null primary key
, player_1 number not null
, player_2 number not null
, match_played date not null
, result varchar2(10)
, constraint match_player1_fk foreign key (player_1) references player
, constraint match_player2_fk foreign key (player_2) references player
);
A foreign key can reference a unique constraint rather than a primary key. However this is not standard practice. It is the convention to use unique keys to enforce candidate keys - business keys - and these are not always suitable for use as foreign keys.
For instance in my example, PLAYER.NAME is a unique key: every player must have a distinct name. However, it would not be appropriate to use NAME as the foreign key on MATCH because people can change their name. It is more convenient to use the synthetic primary key, PLAYER_ID because that will not change over the lifetime of the PLAYER record.
A set of columns comprising a foreign key in one table must refer to an equivalent set of columns in a table with either a Primary Key or Unique Key constraint.
You certainly can have 2 or more FKs in the same table that refer to the same PK or UK. This models a relationship where a child record is related to more than one parent record - e.g. a record representing a biological child might have a FK to the record for their father as well as for their mother.
Note that a unique index is not sufficient for this purpose; a unique constraint is required, otherwise you will get "ORA-02270: no matching unique or primary key for this column-list".

Tables showing up with two: 'one to many' relationships in oracle sql developer

I'm looking through our data and there's a handful of tables in our oracle database that show up with two one to many relationships: http://i.stack.imgur.com/icGcV.png
I'm not sure why this would be happening, and is it something I should look into getting changed or fixed?
(I did not create this database, I am only trying to understand it!)
Too long for a comment, let's see a very simple example:
CREATE TABLE persons
(
id NUMBER PRIMARY KEY,
name VARCHAR2(10)
)
/
CREATE TABLE marriages
(
wife NUMBER REFERENCES persons(id),
husband NUMBER REFERENCES persons(id)
)
/
CREATE TABLE dogs
(
id NUMBER PRIMARY KEY,
name VARCHAR2(10),
owner NUMBER REFERENCES persons(id)
)
/
Here you have one table with two different FKs to the same table. At the same time you have another table with a single FK to the same table.
So, it's not a problem to fix, but a part of DB design to understand;
your DB can be well or bad designed, but the existence of such situations does not say anything about that.

FK on a single column referencing a column from composite PK

Not able to create /find the logic to apply FK on a column in child table referencing a column from composite PK of parent table.
create table product(prod_id number,
prod_name varchar2(20),
price number,
constraint PK12 primary key(prod_id,prod_name));
Table created.
create table purchase(prod_id number,
purchase_price number,
constraint FK12 foreign key(prod_id) references product(prod_id));
create table purchase(prod_id number,
purchase_price number,
constraint FK12 foreign key(prod_id) references product(prod_id))
ERROR at line 1:
ORA-02270: no matching unique or primary key for this column-list
Kinldy suggest how i can incorporate this logic.
Thanks.
You can't.
As the error says there's no matching primary key for that column list; you must have one. You have three options:
Remove PROD_NAME from the primary key of PRODUCT. On the face of it this seems like the logical solution, if this is not required in order to make the primary key unique.
Add PROD_NAME to the PURCHASE table.
Create a unique index on PURCHASE.PROD_ID. This seems excessive if it would be a primary key candidate anyway.
I suspect that this is not unique to Oracle. Considering you have a composite primary key in the referenced table, that implies that only one of the columns comprising the composite key is not enough to uniquely identify the record in that table. Therefore, it's impossible to reference only a single column of the primary key in a foreign key relationship that's one-to-many (e.g. one record in the referenced table can have many records in the referencing table--the one with the FK). However, if the relationship to be established is many-to-many, this may be possible.
HTH.

Bidirectional Foreign Keys Design

Say there are two tables, Company and Employee. Employee has a foreign key to Company and Company has a foreign key to Employee. How should I insert and delete data into these tables without getting referential integrity errors?
COMPANIES
ID
NAME
CONTACT_EMPLOYEE_ID --FK
EMPLOYEES
ID
NAME
COMPANY_ID --FK
I imagine this is a fairly common problem. I have researched it but have been unable to find much information. Perhaps the problem comes under a more common name I am not aware of.
There are several methods available:
Is the CONTACT_EMPLOYEE_ID column nullable? If it is, just insert company, insert employee and then update the company record.
You could also set one of the constraints as deferrable. You could then set the constraint as deferred, insert both records and then commit.
There are generally 2 strategies:
Leave one of the FKs NULL-able (and then insert NULL into that table, insert row into other table and finally update the NULL).
Defer one of the FKs.
You could even leave both FKs NULL-able or deferrable (or even a combination of the two), so you can perform the insertion in both directions.
You could also consider placing all the EMPLOYEES fields into COMPANIES.
Apart from the other suggestions already made, which are good (make one of the FK columns NULLable, or make the FK constraint deferrable), another one is to make the NOT NULL constraint deferrable, e.g.:
create table COMPANIES (
ID number not null,
NAME varchar2(100) not null,
CONTACT_EMPLOYEE_ID number,
constraint contact_not_null
check (CONTACT_EMPLOYEE_ID not null)
deferrable
initially deferred
);
Now, you can insert a row with NULL for the employee id, insert the employee, then update companies.contact_employee_id with the new employee ID, then COMMIT.

How to have unique primary key in two tables?

I have two tables in my system EMPLOYEE and EMPLOYEE_FORECAST. Both have the same columns, entire structure is same. I have another archive table with same structure called EMPLOYEE_ARCHIVE table.
I need to put data from both tables to this archive table. Since records in EMPLOYEE and EMPLOYEE_FORECAST may have same primary key e.g. a record in EMPLOYEE will have a pk of say 100 and another record in EMPLOYEE_FORECAST may also have pk of 100 and this will definitely happen so when they are inserted into archive table I will have a duplicate primary key.
The problem is I will also have some relation table like employee_products, employee_forecast_products and also employee_archive_products. These tables will have emp_id and product_id. So with same emp_id I wont be able to figure out the exact employee.
So, is there any way to have a unique primary key both the EMPLOYEE and EMPLOYEE_FORECAST tables.
So you cannot not use the PK column of EMPLOYEE table as a PK column of the archive table.
You can add a new PK column to the archive table.
If, for some reason, you want the EMPLOYEE table's PK column to be the PK in the archive table, then you could add a flag column to the archive table which would indicate from which table the record comes from. And you could have a composite PK in the archive table containing the original PK and the flag column. (In general, I discourage composite PK-s, so, even if you want to have this flag column, you could have an additional normal PK column in the archive as well.)
To expand on my comment, set up you archive table as:
EMPLOYEE
EMPID NUMBER PK
EMPNAME VARCHAR2(30)
...
EMPLOYEE_FORECAST
EMPID NUMBER PK
EMPNAME VARCHAR2(30)
...
EMPLOYEE_ARCHIVE
ORIG_TABLE VARCHAR2(30) PK
EMPID NUMBER PK
EMPNAME VARCHAR2(30)
...
Data in EMPLOYEE_ARCHIVE:
ORIG_TABLE EMPID EMPNAME
------------------------------------
EMPLOYEE 100 JO BLOGGS
EMPLOYEE_FORECAST 100 JO BLOGGS
As the archive table PK is across both the original table and empid columns it will remain unique for all your data.
Obviously this is just an example and you can use whatever derived column you want to enforce the uniqueness in your archive table.
Hope it helps...
Create a Common Super-Table. Make another table EMPLOYEE_ID with only a primary key. Let both EMPLOYEE, EMPLOYEE_FORECAST and EMPLOYEE_ARCHIVE reference it.
Your data model seems a tad confused. If EMPLOYEE and EMPLOYEE_FORECAST have identical structures why have two tables? What is the business rule here?
And if they are supposed to be two separate tables why store them in a common archive table? Why not have separate archives for each table?
I agree with #Ollie. You need to rethink your data model so it clearly expresses how your business operates. If you post your business rules here I'm sure we can help you untangle things. But here is probably the crucial question: do the following keys identify one employee (i.e one person in the real world) or two?
employee.emp_id = 100
employee_forecast.emp_id = 100

Resources