I have 4 tables
customer: CustomerID - primary key, name
Magazine: name - primary key, cost, noofissues
Newspaper: name - primary key, cost, noofissues
subscription: custID - references CustomerID of Customer, name, startdate, enddate
In the above, can I reference the name from subscription table to reference name from Magazine and name from Newspaper?
I have created the tables Customer, Newspaper and Magazine. I only need to create Subscription.
Can you do something like this?
CREATE TABLE subscription (
custID INT
CONSTRAINT subscription__custid__fk REFERENCES Customer( CustomerId ),
name VARCHAR2(50)
CONSTRAINT subscription__mag_name__fk REFERENCES Magazine( Name )
CONSTRAINT subscription__news_name__fk REFERENCES Newspaper( Name ),
startdate DATE
CONSTRAINT subscription__startdate__nn NOT NULL,
enddate DATE
);
Yes, you can and you will have two foreign keys on the same column pointing to different tables but if the value in the column is non-null then it will expect there to be a matching name in both the magazines table and the newspapers table - which is probably not what you are after.
Can you have a foreign key that asks can the value be in either exclusively in this table or that table (but not in both)? No.
But you can re-factor your database so you merge the newspapers and magazines tables into a single table (which you can then easily reference); like this:
CREATE TABLE customer (
CustomerID INT
CONSTRAINT customer__CustomerId__pk PRIMARY KEY,
name VARCHAR2(50)
CONSTRAINT customer__name__nn NOT NULL
);
CREATE TABLE Publications (
id INT
CONSTRAINT publications__id__pk PRIMARY KEY,
name VARCHAR2(50)
CONSTRAINT publications__name__nn NOT NULL,
cost NUMBER(6,2)
CONSTRAINT publications__cost__chk CHECK ( cost >= 0 ),
noofissues INT,
type CHAR(1),
CONSTRAINT publications__type__chk CHECK ( type IN ( 'M', 'N' ) )
);
CREATE TABLE subscription (
custID INT
CONSTRAINT subscription__custid__fk REFERENCES Customer( CustomerId ),
pubID INT
CONSTRAINT subscription__pubid__fk REFERENCES Publications( Id ),
startdate DATE
CONSTRAINT subscription__startdate__nn NOT NULL,
enddate DATE
);
If you are asking whether you can create a foreign key constraint on subscription that references either the newspaper table or the magazine table, the answer is no, you cannot. A foreign key must reference exactly one primary key.
Since magazine and newspaper have the same set of attributes, the simple option is to combine them into a single periodical table with an additional periodical_type column to indicate whether it is a magazine or a newspaper. You could then create your foreign key to the periodical table.
Although it probably won't make sense in this particular example, you could also have separate columns in subscription for magazine_name and newspaper_name and create separate foreign key constraints on those columns along with a check constraint that ensured that exactly one of the values was non-NULL. That might make sense if the two different parent tables had radically different attributes.
Not related to your question but as a general bit of advice, I wouldn't use the name as the primary key. In addition to being rather long, names tend to change over time and names aren't necessarily unique. I would use a different attribute for the key, potentially a synthetic primary key generated from a sequence.
Related
I am created 2 tables named entry and team based on the attached logical model.
I didn't have any problems with the create table as I created the tables first. altered the table to have the primary keys. and by the end add foreign keys.
CREATE TABLE entry (
event_id NUMBER(6) NOT NULL,
entry_no NUMBER(5) NOT NULL,
entry_starttime DATE,
entry_finishtime DATE,
comp_no NUMBER(5) NOT NULL,
team_id NUMBER(3),
char_id NUMBER(3)
);
ALTER TABLE entry ADD CONSTRAINT entry_pk PRIMARY KEY ( event_id,
entry_no );
CREATE TABLE team (
team_id NUMBER(3) NOT NULL,
team_name VARCHAR(30) NOT NULL,
carn_date DATE NOT NULL,
team_no_members NUMBER(2) NOT NULL,
event_id NUMBER(6) NOT NULL,
entry_no NUMBER(5) NOT NULL,
char_id NUMBER(3)
);
ALTER TABLE team ADD CONSTRAINT team_pk PRIMARY KEY ( team_id );
ALTER TABLE team ADD CONSTRAINT team_nk UNIQUE ( team_name,
carn_date );
ALTER TABLE entry
ADD CONSTRAINT team_entry FOREIGN KEY ( team_id )
REFERENCES team ( team_id );
ALTER TABLE team
ADD CONSTRAINT entry_team FOREIGN KEY ( event_id,
entry_no )
REFERENCES entry ( event_id,
entry_no );
My problems come in when i start inserting values to the tables.
team_no is a foreign key in entry table (but could be null). event_id and entry_no are foreign keys (not null) in team table.
INSERT INTO entry (
event_id,
entry_no,
entry_starttime,
entry_finishtime,
comp_no,
team_id,
char_id
) VALUES (
6,
2,
TO_DATE('08:30', 'HH:MI'),
TO_DATE('08:50', 'HH:MI'),
10,
NULL,
1
);
INSERT INTO team (
team_id,
team_name,
carn_date,
team_no_members,
event_id,
entry_no,
char_id
) VALUES (
5,
'Turner Hall',
TO_DATE('24/SEP/2021', 'DD/MON/YYYY'),
2,
2,
1,
4
);
it gives me a ORA-02291: integrity constraint (string.string) violated - parent key not found error.
How can I fix this?
Thanks!
Fix your design first.
Start out with some simple sentences that define the what each thing is (Carnival, Event, Entry, Team, Competitor, Charity).
Once you know what they mean then you can write some more simple sentences defining the relationships.
Only once you have it straight in your head what everything is and how it is related then you can create the entity-relationship diagram and that diagram should be a visual representation that has a 1:1 correspondence to your simple sentence descriptions.
If you find you want to add a constraint in the ER diagram that does not have a description then write the simple sentence description first and think long and hard about whether what you have written makes logical sense; if it does not then do not add the relationship.
So you can start with:
There are people (Competitors).
The Competitors are grouped into multiple Teams.
Each Team can have many members (Competitors) but exactly one of those is the team leader.
There are Carnivals.
Each Carnival can host multiple competitive Events.
An Event requires an Entry from each Team.
Each Team can have multiple Entrys into different Events.
Each Team can only have one Entry into each Event.
Each Event can have multiple Entry from different teams.
Each Team supports exactly one Charity.
From that description, there is no mention of competitors and events in the same relationship so, if that was the case, then in your ER diagram there should not be any direct relationship between competitors and events; instead there are relationships from each to a team.
Similarly, the team leader relationship is from a Team to a Competitor and not to an Entry.
You may have different ideas of what the tables and relationships mean but you will find that by setting everything out in simple sentences it will force you to understand what everything means and making sure it makes sense.
Once you fix your design then you will find that you have eliminated the problem of cyclic references that prevent you from inserting data without disabling constraints.
CREATE TABLE Flight (
FlightNo int NOT NULL PRIMARY KEY,
FlightDate Date,
PlaneSerialNo int,
EmployeeID int,
RouteNo int,
CONSTRAINT FK_PlaneSerialNo FOREIGN KEY(PlaneSerialNo)
REFERENCES Plane(PlaneSerialNo),
CONSTRAINT FK_EmployeeID FOREIGN KEY(EmployeeID)
REFERENCES Employee(EmployeeID),
CONSTRAINT FK_RouteNo FOREIGN KEY(RouteNo)
REFERENCES Route(RouteNo)
);
trying to create a sort of database system using oracle where it tracks flights but it just says the name is already used but havent seen any similarities in constraints other than identifying FKs
Oracle doesn't rely much on similarities - it has found object with exactly the same name in its dictionary and - as you can't have two objects with the same name - it raised the error.
Query user_constraints (and then user_objects, if previous search didn't find anything).
If you want to find out which table it is, you might try
select owner, table_name from dba_constraints where constraint_name = '<some value from your create table command>';
CREATE TABLE Route(
RouteNo VARCHAR(10),
Origin VARCHAR(30),
Destination VARCHAR(30),
DepartureTime VARCHAR(15),
SerialNo VARCHAR(5),
ArrivalTime VARCHAR(15),
PRIMARY KEY(RouteNo) );
CREATE TABLE Employee(
EmployeeID VARCHAR(5) NOT NULL,
Name VARCHAR(30),
Phone NUMBER,
JobTitle VARCHAR(30),
PRIMARY KEY(EmployeeID) );
CREATE TABLE Flight(
SerialNo VARCHAR(5),
RouteNo VARCHAR(5),
FlightDate DATE,
ActualTD VARCHAR(10),
ActualTA VARCHAR(10),
PRIMARY KEY(SerialNo, RouteNo, FlightDate),
FOREIGN KEY(RouteNo) REFERENCES Route(RouteNo),
FOREIGN KEY(SerialNo) REFERENCES Airplane(SerialNo) ); -- does Airplane table exists ?
CREATE TABLE CrewAssigment(
EmployeeID VARCHAR(5),
RouteNo VARCHAR(5),
FlightDate DATE,
Role VARCHAR(45),
Hours INT,
PRIMARY KEY(EmployeeID, RouteNo, FlightDate),
FOREIGN KEY(EmployeeID) REFERENCES Employee(EmployeeID),
FOREIGN KEY(RouteNo) REFERENCES Route(RouteNo),
FOREIGN KEY(FlightDate) REFERENCES Flight(FlightDate) );
Select * from CrewAssignment
This is my code where I'm getting an error in the CrewAssignment table and above are the tables where the foreign key is referenced from.
Error report -
ORA-02270: no matching unique or primary key for this column-list
02270. 00000 - "no matching unique or primary key for this column-list"
*Cause: A REFERENCES clause in a CREATE/ALTER TABLE statement
gives a column-list for which there is no matching unique or primary
key constraint in the referenced table.
*Action: Find the correct column names using the ALL_CONS_COLUMNS
catalog view
A few objections.
This is clearly an Oracle question, not MySQL. How do I know? ORA-02270 is an Oracle database error code; pay attention to tags you use.
You should use VARCHAR2 datatype instead of VARCHAR. Why? Oracle recommends so.
create table flight fails first as it references the airplane table, and it doesn't exist yet (at least, not in code you posted)
error you're complaining about is due to create table crewassignment. One of its foreign keys references the flight table:
FOREIGN KEY(flightdate) REFERENCES flight(flightdate)
but flight's primary key is composite, made up of 3 columns:
PRIMARY KEY(serialno,
routeno,
flightdate)
which means that you can't create that foreign key.
So, what to do? No idea, I don't know rules responsible for such a data model. Either modify primary key of the flight table, or modify foreign key constraint of the crewassingment table.
Perhaps you could add a new column to flight table (made up of a sequence (or identity column, if your database version supports it) and then let the crewassignment table reference that primary key. Columns you currently use as a primary key (serialno, routeno, flightdate) would then switch to unique key.
I am new to here, please help me to find an answer to the below query.
"How to add a primary key constraint on two columns to make a composite key column in a table?"
Instead of writing so many lines, kindly provide the answer as short as possible with code.
(I am creating a table in which I can have only one primary key on the values of two-columns as a composite key.)
JacknJill
You can create such constraint in scope of CREATE TABLE operator
CREATE TABLE foo (
id INTEGER,
name VARCHAR(25),
bar VARCHAR(255),
CONSTRAINT foo_pk PRIMARY KEY (id,name)
);
or ALTER TABLE operator
CREATE TABLE foo (
id INTEGER,
name VARCHAR(25),
bar VARCHAR(255)
);
ALTER TABLE foo ADD CONSTRAINT foo_pk PRIMARY KEY (id,name);
I'm working on a set of database tables in Oracle and trying to figure out a way to enforce referential integrity with slightly polymorphic data.
Specifically, I have a bunch of different tables--hypothetically, let's say I have Apples, Bananas, Oranges, Tangerines, Grapes, and a hundred more types of fruit. Now I'm trying to make a table which describes performing steps involving a fruit. So I want to insert one row that says "eat Apple ID 100", then another row which says "peel Banana ID 250", then another row which says "refrigerate Tangerine ID 500", and so on.
Historically, we've done this in two ways:
1 - Include a column for each possible type of fruit. Use a check constraint to ensure that all but one column is NULL. Use foreign keys to ensure referential integrity to our fruit. So in my hypothetical example, we'd have a table with columns ACTION, APPLEID, BANANAID, ORANGEID, TANGERINEID, and GRAPEID. For the first action, we'd have a row 'Eat', 100, NULL, NULL, NULL, NULL, NULL. For the second action, we'd have 'Peel', NULL, 250, NULL, NULL, NULL. etc. etc.
This approach is great for getting all of Oracle's RI benefits automatically, but it just doesn't scale to a hundred types of fruit. You end up getting too many columns to be practical. Just figuring out which type of fruit you are dealing with becomes a challenge.
2 - Include a column with the name of the fruit, and a column with a fruit ID. This works also, but there isn't any way (AFAIK) to have Oracle enforce the validity of the data in any way. So our columns would be ACTION, FRUITTYPE, and FRUITID. The row data would be 'Eat', 'Apple', 100, then 'Peel', 'Banana', 250, etc. But there's nothing preventing someone from deleting Apple ID 100, or inserting a step saying 'Eat', 'Apple', 90000000 even though we don't have an Apple with that ID.
Is there a way to avoid maintaining a separate column per each individual fruit type, but still preserve most the benefits of foreign keys? (Or technically, I could be convinced to use a hundred columns if I can hide the complexity with a neat trick somehow. It just has to look sane in day-to-day use.)
CLARIFICATION: In our actual logic, the "fruits" are totally disparate tables with very little commonality. Think customers, employees, meetings, rooms, buildings, asset tags, etc. The list of steps is supposed to be free-form and allow users to specify actions on any of these things. If we had one table which contained each of these unrelated things, I wouldn't have a problem, but it would also be a really weird design.
It's not clear to me why you need to identify the FRUIT_TYPE on the TASKS table. On the face of it that's just a poor (de-normalised) data model.
In my experience, the best way of modelling this sort of data is with a super-type for the generic thing (FRUIT in your example) and sub-types for the specifics (APPLE, GRAPE, BANANA). This allows us to store common attributes in one place while recording the particular attributes for each instance.
Here is the super-type table:
create table fruits
(fruit_id number not null
, fruit_type varchar2(10) not null
, constraint fruit_pk primary key (fruit_id)
, constraint fruit_uk unique (fruit_id, fruit_type)
, constraint fruit_ck check (fruit_type in ('GRAPE', 'APPLE', 'BANANA'))
)
/
FRUITS has a primary key and a compound unique key. We need the primary key for use in foreign key constraints, because compound keys are a pain in the neck. Except when they are not, which is the situation with these sub-type tables. Here we use the unique key as the reference, because by constraining the value of FRUIT_TYPE in the sub-type we can guarantee that records in the GRAPES table map to FRUITS records of type 'GRAPE', etc.
create table grapes
(fruit_id number not null
, fruit_type varchar2(10) not null default 'GRAPE'
, seedless_yn not null char(1) default 'Y'
, colour varchar2(5) not null
, constraint grape_pk primary key (fruit_id)
, constraint grape_ck check (fruit_type = 'GRAPE')
, constraint grape_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
, constraint grape_flg_ck check (seedless_yn in ('Y', 'N'))
)
/
create table apples
(fruit_id number not null
, fruit_type varchar2(10) not null
, apple_type varchar2(10) not null default 'APPLE'
, constraint apple_pk primary key (fruit_id)
, constraint apple_ck check (fruit_type = 'APPLE')
, constraint apple_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
, constraint apple_type_ck check (apple_type in ('EATING', 'COOKING', 'CIDER'))
)
/
create table bananas
(fruit_id number not null
, fruit_type varchar2(10) not null default 'BANANA'
, constraint banana_pk primary key (fruit_id)
, constraint banana_ck check (fruit_type = 'BANANA')
, constraint banana_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
)
/
In 11g we can make FRUIT_TYPE a virtual column for the sub-type and do away with the check constraint.
So, now we need a table for task types ('Peel', 'Refrigerate', 'Eat ', etc).
create table task_types
(task_code varchar2(4) not null
, task_descr varchar2(40) not null
, constraint task_type_pk primary key (task_code)
)
/
And the actual TASKS table is a simple intersection between FRUITS and TASK_TYPES.
create table tasks
(task_code varchar2(4) not null
, fruit_id number not null
, constraint task_pk primary key (task_code, fruit_id)
, constraint task_task_fk ask foreign key (task_code)
references task_types (task_code)
, constraint task_fruit_fk foreign key (fruit_id)
references fruit (fruit_id)
/
If this does not satisfy your needs please edit your question to include more information.
"... if you want different tasks for different fruits..."
Yes I wondered whether that was the motivation underlying the OP's posted design. But usually workflow is a lot more difficult than that: some tasks will apply to all fruits, some will only apply to (say) fruits which come in bunches, others will only be relevant to bananas.
"In our actual logic, the 'fruits' are totally disparate tables with
very little commonality. Think customers, employees, meetings, rooms,
buildings, asset tags, etc. The list of steps is supposed to be
free-form and allow users to specify actions on any of these things."
So you have a bunch of existing tables. You want to be able to assign records from these tables to tasks in a freewheeling style yet be able to guarantee the identify of the specific record which owns the task.
I think you still need a generic table to hold an ID for the actor in the task, but you will need to link it to the other tables somehow. Here is how I might approach it:
Soem sample existing tables:
create table customers
(cust_id number not null
, cname varchar2(100) not null
, constraint cust_pk primary key (fruit_id)
)
/
create table employees
(emp_no number not null
, ename varchar2(30) not null
, constraint emp_pk primary key (fruit_id)
)
/
A generic table to hold actors:
create table actors
(actor_id number not null
, constraint actor_pk primary key (actor_id)
)
/
Now, you need intersection tables to associate your existing tables with the new one:
create table cust_actors
(cust_id number not null
, actor_id number not null
, constraint cust_actor_pk primary key (cust_id, actor_id)
, constraint cust_actor_cust_fk foreign key (cust_id)
references customers (cust_id)
, constraint cust_actor_actor_fk foreign key (actor_id)
references actors (actor_id)
)
/
create table emp_actors
(emp_no number not null
, actor_id number not null
, constraint emp_actor_pk primary key (emp_no, actor_id)
, constraint emp_actor_emp_fk foreign key (emp_no)
references eployees (emp_no)
, constraint cust_actor_actor_fk foreign key (actor_id)
references actors (actor_id)
)
/
The TASKS table is rather unsurprising, given what's gone before:
create table tasks
(task_code varchar2(4) not null
, actor_id number not null
, constraint task_pk primary key (task_code, actor_id)
, constraint task_task_fk ask foreign key (task_code)
references task_types (task_code)
, constraint task_actor_fk foreign key (actor_id)
references actors (actor_id)
/
I agree all those intersection tables look like a lot of overhead but there isn't any other way to enforce foreign key constraints. The additional snag is creating ACTORS and CUSTOMER_ACTORS records every time you create a record in CUSTOMERS. Ditto for deletions. The only good news is that you can generate all the code you need.
Is this solution better than a table with one hundred optional foreign keys? Perhaps not: it's a matter of taste. But I like it better than having no foreign keys at all. If there is on euniversal truth in database practice it is this: databases which rely on application code to enforce relational integrity are databases riddled with children referencing the wrong parent or referencing no parent at all.