Nested table primary and foreign key in Oracle - sql

I'm trying to add a primary and foreign key to a nested table, struggling to know how.
This is what I have;
create or replace type profile as object
(
id VARCHAR2(10), --- Suppose to be Primary Key
userID VARCHAR2(10) --- Suppose to be Foreign Key for user table
);
create or replace type profile_nest as table of profile;
CREATE OR REPLACE TYPE user_t UNDER group_T
(profile profile_nest_ty,);
CREATE TABLE user OF user_t
(id NOT NULL,
PRIMARY KEY (id),
nested table profile store as profile_storage_tbl;
Now the problem is this part, trying to do a foreign key -
alter table profile_storage_tbl add CONSTRAINT fk_userID FOREIGN KEY (userID)
REFERENCES user(id);
Gives this error -
*Error starting at line 3 in command:
alter table profile_storage_tbl add CONSTRAINT fk_userID FOREIGN KEY (userID)
REFERENCES user(id)
Error report:
SQL Error: ORA-30730: referential constraint not allowed on nested table column
30730. 00000 - "referential constraint not allowed on nested table column"
*Cause: An attempt was made to define a referential constraint on a nested
table column.
Action: Do not specify referential constraints on nested table columns.

Either you create 2 separate tables profile_storage_tbl and user with a foreign key between them or you create profile_storage_tbl as a nested table within the user table. It doesn't make sense to try to do both. (In fact nested tables make little sense to me, period - but that's another matter!)

It is just as the exception text says, creating a foreign key constraint on nested table columns is not allowed (Oracle 11).
There is sort of a workaround described here: http://ksun-oracle.blogspot.com/2011/05/foreign-key-on-nested-table.html. But there is no guarantee, that this would work on the next oracle release.

Behind the scene oracle will create two tables profile_storage_tbl and user whereas profile_storage_tbl has a foreign key on user.
You can do that on your own, with the advatage to have better control over the releations (also to other tables).

Related

Efficiently enforcing a 1:1 relationship between two rows with foreign key constraints without creating redundant unique indexes

I have two PostgreSQL tables designed in the following way:
create type content_owner as enum (
'document',
'task'
);
create table content (
id serial not null primary key,
owner content_owner not null,
owner_document_id int references document(id) deferrable initially deferred,
owner_task_id int references task(id) deferrable initially deferred,
-- ...
constraint collab_content_owner_document
check (owner_document_id is null or (owner = 'document' and owner_document_id is not null)),
constraint collab_content_owner_task
check (owner_task_id is null or (owner = 'task' and owner_task_id is not null))
);
create table document (
id serial not null primary key,
content_id int not null references content(id),
-- ...
);
create table task (
id serial not null primary key,
content_id int not null references content(id),
-- ...
);
I want to enforce a 1:1 relationship at the database level for the document<->content relationship and the task<->content relationship.
Adding the following constraints accomplishes that:
alter table collab_content add foreign key (owner_document_id, id) references document (id, content_id) deferrable initially deferred;
alter table collab_content add foreign key (owner_task_id, id) references task (id, content_id) deferrable initially deferred;
alter table document add foreign key (content_id, id) references collab_content (id, owner_document_id);
alter table task add foreign key (content_id, id) references collab_content (id, owner_task_id);
Since I’m saying the ID pair should reference the same ID pair in the other table for both directions. However, this also requires me to create the following indexes:
alter table document add unique (id, content_id);
alter table task add unique (id, content_id);
alter table collab_content add unique (id, owner_document_id);
alter table collab_content add unique (id, owner_task_id);
These indexes feel pretty redundant given that there’s already a primary key on the id columns for these tables. It feels like PostgreSQL should be smart enough to be able to use the existing primary key constraint to make sure the foreign key constraints are met. Ideally I wouldn’t create a second, redundant, index on these tables for the purpose of these foreign key constraints.
Is there a way for me to avoid creating new unique indexes and instead tell PostgreSQL to only lookup the unique ID when resolving the foreign key?
Will PostgreSQL detect that these unique indexes are redundant (because the first column is the primary key) and not materialize a new index on disk for their purpose?
Is there a better way to enforce this constraint?
Two-way linking like this is a recipe for headaches. I recommend avoiding reference cycles if you can. In your case, the simplest way to store this information is to relax the constraint that there cannot be a content without a document or a task. Ask yourself, how might such a situation occur, how else could it be avoided, and what damage might it cause if it happens?
If we can remove that constraint, then we can have a very simple structure where document and task each have a content_id foreign key, and a unique index on it to ensure that no two documents have the same content.
If we can't remove that constraint, then the answers to your questions are:
There is no way to avoid creating those new unique indexes for the foreign keys. Foreign keys must have matching unique indexes.
Postgres will not detect that these indexes are redundant, and they will indeed be materialized and take up space.

Can FOREIGN KEY be omitted in PostgreSQL when using REFERENCES?

I'm wondering if there's any (maybe subtle) difference between these two SQL statements:
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
and
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
user_id INTEGER NOT NULL REFERENCES users(user_id)
);
I've noticed that when I create a table in Postico with the first notation, but look at the DDL of the created profiles table later, the FOREIGN KEY is removed and I end up with the shorter second notation.
Create table with FOREIGN KEY:
DDL view doesn't show FOREIGN KEY:
So, I'm wondering (and seeking confirmation) that the two statements are in fact 100% equivalent or if there are some subtle differences in what they do to the DB.
Any pointer to official resources (and maybe also how that differs from MySQL) would be appreciated.
The two samples you show do the same thing, just with a different syntax.
The first method is called table constraint, the second column constraint, but the latter name is somewhat misleading because the constraint is on the table as well.
The main difference is that the column constraint syntax is shorter, but cannot be used for all constraints: if you have for example a primary key that contains two columns, you have to write it in the table constraint syntax.
DDL view doesn't show FOREIGN KEY
DDL view created by unknown third-party tool in not an argument.
See fiddle. Foreign key exists in both cases. Moreover, I do not see the result difference for both DDL queries.
PS. As a recommendation - always specify the constraint name explicitly. What if you need to delete it? It is problematic without the constraint name...
In PostgreSQL, you define a foreign key through a foreign key constraint. A foreign key constraint indicates that values in a column or a group of columns in the child table match with the values in a column or a group of columns of the parent table. We say that a foreign key constraint maintains referential integrity between child and parent tables.
This may explain to you better or you can read about Foreign Keys documentation .

Create a table in SQL where the Composite Primary Key is also a Foreign Key

I need to create a table called LFM_Enroll in SQL that has a composite primary key of Student_ID and Section_Number. Student_ID is also a foreign key, it references Student_ID in the LFM_Student table and Section_Number is also a foreign key, it references Section_Number in the LFM_Section table. How do I write the constraints and foreign keys? I've attached an image of the tables and below is what I have done so far. After the LFM_Enroll table is created I need to update one row. I tried doing so but kept getting the below error.
: Error starting at line : 173 in command -
UPDATE LFM_Enroll
SET Student_ID = 1234567,
Section_Number = 01234
WHERE Student_ID = 900000 AND Section_Number = 4138
Error report -
ORA-02291: integrity constraint (SYSTEM.FK_LFM_ENROLL_SECTION_NUMBER) violated - parent key not found.
Tables Thanks in advance for all your help.
CREATE TABLE LFM_Enroll (
Student_ID char(7),
Section_Number char(4),
constraint PK_LFM_Enroll Primary Key (Student_ID,Section_Number),
constraint FK_LFM_Enroll_Student_ID
Foreign Key (Student_ID,Section_Number) references LFM_Student (Student_ID),
constraint FK_LFM_Enroll_Section_Number
Foreign Key (Student_ID,Section_Number) references LFM_Section (Section_Number)
);
Your foreign key constraints are not right. You are trying to map two columns {Student_ID,Section_Number} to a single column LFM_Student.Student_ID.
The number of columns in the principal key must match the number of columns in the foreign key. In other words, the key LFM_Student is one column (Student_ID), so the foreign key also needs to be a single matching column - in this case LFM_Enroll.Student_ID. Correct DDL would be:
constraint FK_LFM_Enroll_Student_ID
Foreign Key (Student_ID) references LFM_Student (Student_ID),
constraint FK_LFM_Enroll_Section_Number
Foreign Key (Section_Number) references LFM_Section (Section_Number)
I'm not quite sure why your RDBMS is allowing what you have, but it may be using the first column and simply ignoring the second. In which case FK_LFM_Enroll_Section_Number is creating a foreign key LFM_Enroll.Student_ID => LFM_Section.Section_Number.
The error indicates that the values with which you are trying to update the two columns may not exist in Student and / or Sections tables i.e. 1234567 doesn't exists in the student table and / or 01234 doesn't exist in your section table . You should try inserting new rows or updating existing ones with the new values you are trying to update your foreign keys with.
[Edit: For defining constraints refer lc.'s post]

Can't add foreign keys because unique constraint needed

I'm brand new to using Oracle SQLDeveloper and I'm working on a college project right now. I keep trying to add foreign key constraints to my tables(which already hold the foreign key as an attribute) so Im using ALTER like this:
alter table applies
add constraint e_number foreign key (e_number)
references student (e_number);
where e_number is the primary key in a table called student. The student table's e_number has the primary key constraint and also has an index that was auto-generated where it says UNIQUE under the UNIQUENESS column in the indexes tab. Whenever I try and create a foreign key for any of my tables I'm getting this same error everytime:
Error starting at line : 1 in command -
alter table applies
add constraint e_number foreign key (e_number)
references student (e_number)
Error report -
SQL Error: ORA-02264: name already used by an existing constraint
02264. 00000 - "name already used by an existing constraint"
*Cause: The specified constraint name has to be unique.
*Action: Specify a unique constraint name for the constraint.
I'm a bit confused and have been reading about unique on several sites but still don't get it. When I call an ALTER I can either specify a FOREIGN key or specify a UNIQUE key. Am I supposed to ALTER unique and then ALTER foreign? What am I doing wrong?
It's because you already have a key named e_number. Try:
alter table applies
add constraint applies_student_e_number foreign key (e_number)
references student (e_number);

Is there any way to make the following sql query work?

I am trying to create two tables using the following SQL:
create table student(sid char(20) primary key,name char(20),age int,hours char(10) references courses(cid));
create table courses(cid char(10),cname char(10),grader char(20) references student(sid));
However I get the following error:
1: ERROR: relation "courses" does not exist
3: ERROR: relation "student" does not exist
Is there any way or syntax which can solve this problem?
You would need to create the tables first (without REFERENCES clause). After that create your foreign keys manually by statement ALTER TABLE mytable ADD CONSTRAINT mytablefk FOREIGN KEY... But first I'd consider if there really is a relationship from table courses to table student!
Rather than creating the Foreign Key constraints at the same time as the tables with the References short-hand, you can add one or both of them afterwards with an Alter Table Add Constraint command. See the Alter Table page in the PostgrSQL manual here.
As mu pointed out, the target of a foreign key has to have a Unique or Primary Key constraint defined, so I've added that on the cid column in the example below.
In your case, it could look something like this:
create table student(sid char(20) primary key,name char(20),age int,hours char(10));
create table courses(cid char(10) primary key,cname char(10),grader char(20));
Alter Table student Add Constraint fk_student_hours_cid Foreign Key (hours) References courses(cid);
Alter Table courses Add Constraint fk_courses_grader_sid Foreign Key (grader) References student(sid);