I am trying to make a object relational database of a school enrolment system in oracle 11g, my sql code is below. I am trying to write a query that gives back the course name and students enrolled in that course. but when i try to add another chemistry class, with the id 101. i get an error. this is because i have made courseID a primary key, so i cant insert multiple courses with that course id? So can anyone show me how i can create multiple chemistry insert statements with the same id, but different student id?
CREATE TYPE Student_objtyp AS OBJECT (
FName VARCHAR2(20),
LName VARCHAR2(20),
StudentID NUMBER
);
/
CREATE TABLE Student_objtab OF Student_objtyp (StudentID PRIMARY KEY)
OBJECT IDENTIFIER IS PRIMARY KEY;
CREATE TYPE Course_objtyp AS OBJECT (
CourseName VARCHAR(20),
CourseID NUMBER,
StudentID REF Student_objtyp
);
/
CREATE TABLE Course_objtab OF Course_objtyp (
PRIMARY KEY (CourseID),
FOREIGN KEY (StudentID) REFERENCES Student_objtab)
OBJECT IDENTIFIER IS PRIMARY KEY;
INSERT INTO Student_objtab VALUES('bill','smitts',1);
INSERT INTO Student_objtab VALUES('bob','jo',2);
INSERT INTO Course_objtab
SELECT 'Chemistry',101,
REF(S)
FROM Student_objtab S
WHERE S.StudentID = 1;
INSERT INTO Course_objtab
SELECT 'Chemistry',101,
REF(S)
FROM Student_objtab S
WHERE S.StudentID = 2;
INSERT INTO Course_objtab
SELECT 'Physics',201,
REF(S)
FROM Student_objtab S
WHERE S.StudentID = 1;
select c.CourseName, c.StudentID
from Course_objtab c;
This design violates database normalization rules. COURSE should only hold information on the course, NOT on the students enrolled in the course. IMO there should at least be an ENROLLMENT table, with references to COURSE and STUDENT. This is known as a "junction table".
I'd model it as follows:
STAFF - information about staff members (teachers/professors, etc)
STUDENT - information about students
COURSE - information about courses which may be taught
CLASS - information about a specific instance of a course, including the days/times the class meets, the location, and the staff member who is teaching it.
CLASS_ENROLLMENT - relates STUDENTs to a specific CLASS.
There should also probably be something here about ROOM, and ROOM_SCHEDULE, and perhaps an ACADEMIC_CALENDAR.
Best of luck.
You need to spend some time thinking about the structure of your database. From what you described, you need at least three tables. Courses, with PK course_id, students, with PK student_id, and enrollment, with foreign keys course_id and student_id, referencing their respective tables.
Since your course_objtab table contains the students enrolled in a course, the PK should probably be the courseID and StudentID:
CREATE TABLE Course_objtab OF Course_objtyp (
PRIMARY KEY (CourseID, studentID),
FOREIGN KEY (StudentID) REFERENCES Student_objtab)
OBJECT IDENTIFIER IS PRIMARY KEY;
Related
I am going to develop an attendance portal for my university. I have tried but was unsuccessful in designing an efficient DB for the same. It must be able to record attendance for all subjects, all classes etc.
Any leads will be appreciated.
Class --< Lecuture --< Attendance >-- Student
A Class has many Lectures, each Lecture belongs to only a single Class.
Each Student attends many Lectures, and each Lecture is attended by many Students.
CREATE TABLE class (
class_id INT,
class_name VARCHAR(100),
CONSTRAINT class_id_pk PRIMARY KEY (class_id)
);
CREATE TABLE lecture (
lecture_id INT,
class_id INT,
lecture_dt DATE,
CONSTRAINT lecture_id_pk PRIMARY KEY (lecture_id),
CONSTRAINT lecture_class_id_fk FOREIGN KEY (class_id) REFERENCES class (class_id)
);
CREATE TABLE student (
student_id INT,
student_first_name VARCHAR(20),
student_last_name VARCHAR(20),
CONSTRAINT student_id_pk PRIMARY KEY (student_id)
);
CREATE TABLE attendance (
lecture_id INT,
student_id INT,
attendance_present INT CHECK (attendance_present in (0,1)),
CONSTRAINT attendance_pk PRIMARY KEY (lecture_id, student_id),
CONSTRAINT att_lecture_id_fk FOREIGN KEY (lecture_id) REFERENCES lecture (lecture_id),
CONSTRAINT att_student_id_fk FOREIGN KEY (student_id) REFERENCES student (student_id)
);
To create a M:N relationship between student and lecture, create an association table called attendance. Note that the Primary Key of attendance is both the lecture_id and student_id, and that both of these fields have foreign keys back to their respective tables.
If your database has a boolean data type, you could use that for attendance_present. A value of False/0 indicates that the student missed the lecture. A value of True/1 indicates that the student attended. You could also include a on_time if you wanted to store that.
In reality, this would also need a Teacher table which had a many to many with Class. There would probably also need to be a Course (or Subject) Table with a one to many with Class. There could also be a Semester Table with a one to many with Course. A Class could also have a list of Students, so a ClassList association table would be good.
Semester --< Course --< Class --< Lecture --< Attendance >-- Student
Teacher ---^ L--< ClassList---------------------^
I have 4 SQL tables: User, Student, Professor and Publication.
User has the common columns for any kind of user;
Student has columns specific for a student;
Professor has columns specific for a professor;
Publication is only for professors.
So I have:
create table dbo.[User] (
Id int identity not null
constraint PK_User_Id primary key clustered (Id),
-- Other user columns
)
create table dbo.Student (
UserId int not null
constraint PK_Student_UserId primary key clustered (Id),
-- Other student columns
)
create table dbo.Professor (
UserId int not null
constraint PK_Professor_Id primary key clustered (Id),
-- Other student columns
)
create table dbo.Publication (
Id int identity not null
constraint PK_Publication_Id primary key clustered (Id),
UserId int not null
-- Other student columns
)
alter table dbo.Student
add constraint FK_Student_UserId foreign key (UserId) references dbo.[User](Id);
alter table dbo.Professor
add constraint FK_Professor_UserId foreign key (UserId) references dbo.[User](Id);
alter table dbo.Publication
add constraint FK_Publication_UserId foreign key (UserId) references dbo.Professor(Id);
QUESTION
Should I have a column Id as PK in Professor and Student tables?
And make, for example, (Id, UserId) as the PK of Professor (Same for student)
Then Publication would reference Professor.Id and not Professor.UserId.
I am asking this because it sounds strange to have Publication to reference UserId from Professor table which can be confusing when I will have more tables.
Could someone please advice me on this?
In your current schema arrangement and without knowing your use cases (programmatically), one could make the argument that you don't need the Id identity columns for any of the extension tables. I assume this would be a 1 to 1 relationship to the User table anyway, so you'd at least want a unique constraint on the UserID columns, which you'd get by making it a PK anyway.
Things I like to consider are:
Can a professor ever become a different user ?
Is it possible for a professor to exist without an user ?
Is it possible for a single user to be two professors (multiple disciplines?)
If so, why wouldn't you give every professor an unique Id (ProfessorId), and only create a foreign key to the User table (UserId, you could call this UserFk).
In the publication table you can reference the professor by his/her id and call this one ProfessorFk. This way you create very efficient references between tables. The publication table than also gets a single PublicationId as primary key.
Correct me if i'm wrong, i don't know your use case. But it would seem reasonable that a professor can have multiple publications, but a publication can also be written by multiple professors ? This would mean you need an extra table between publication and professor for the n-n relationship.
About creating a professor key that is a combined key (Id, UserId). I personally dislike combined keys, if you want to reference this professor from your publication table you need two columns.
This would also suggest you can have multiple professors for the same user, if so, go for the single Id option.
This means i would create the following setup:
User Table
UserId
Student Table
StudentId
UserFk
Professor Table
ProfessorId
UserFk
ProfessorPublication Table
ProfessorFk
PublicationFk
Publication Table
PublicationId
So, it partly is based on what you want to be able to do with your data, and partly just your preference.
Suppose I have two tables: A (with columns: a,b,c,d) and B (with columns: x,y,z). Now, (a,b) together make the primary key for table A and x is the primary key of table B. Is it possible to make b a foreign key of table A that refers x from table B?
Please reply ASAP!
Thanks in advance! :-)
Yes, there is no issue with that. A classic example (using MySQL for demonstration purposes) is a database table holding a number of companies and another holding employees which can work for any one of those companies:
create table companies (
id int primary key,
name varchar(20));
create table employees (
id int,
c_id varchar(20) references companies(id),
name varchar(20),
primary key (id, c_id));
insert into companies (id, name) values (1, 'ABC');
insert into companies (id, name) values (2, 'DEF');
insert into companies (id, name) values (3, 'HIJ');
insert into employees (id, c_id, name) values (101, 1, "Allan");
insert into employees (id, c_id, name) values (102, 1, "Bobby");
insert into employees (id, c_id, name) values (101, 2, "Carol");
insert into employees (id, c_id, name) values (101, 3, "David");
Note that the primary key for employees is a composite key made up of the employee ID and company ID. Note also that the company ID is a foreign key constraint on the primary key of companies, the exact situation (functionally) that you asked about.
The query showing who works for what company shows this in action:
select c.id, c.name, e.id, e.name
from companies c, employees e
where c.id = e.c_id
order by c.id, e.id
c.id c.name e.id e.name
---- ------ ---- ------
1 ABC 101 Allan
1 ABC 102 Bobby
2 DEF 101 Carol
3 HIJ 101 David
Can a column in a composite primary key also be a foreign key referencing a primary key of another table? Of course it can. The important question is, when is this a good idea?
The most common scenario is probably the intersection or junction table. Customers can have more than one Address (Shipping, Billing, etc) and Addresses can have more than one Customer using them. So the table CUSTOMER_ADDRESSES has a primary key which references both CUSTOMER and ADDRESS primary key (and for bonus points the ADDRESS_TYPE reference data table too).
My examples use Oracle 12c syntax:
create table customer_address
( customer_id number(38,0) not null
, address_id number(38,0) not null
, address_type_code varchar2(3) not null
, constraint customer_address_pk primary key
(customer_id, address_id, address_type_code)
, constraint customer_address_customer_fk foreign key
(customer_id) references customer(customer_id)
, constraint customer_address_address_fk foreign key
(address_id) references address(address_id)
, constraint customer_address_type_fk foreign key
(address_type_code) references address_type(address_type_code)
);
The second scenario occurs when the primary key of the child table is comprises the parent key and an identifier (usually a number) which is only unique within the parent key. For instance, an Order has an Order Header and some Order Lines. The Order is identified by the Order Header ID and its lines are identified by a monotonically incrementing number. The ORDER_LINE table may look like this:
create table order_line
( order_header_id number(38,0) not null
, order_line_no number(38,0) not null
, product_id number(38,0) not null
, qty number(38,0) not null
, constraint order_line_pk primary key
(order_header_id, order_line_no)
, constraint order_line_header_fk foreign key
(order_header_id) references order_header(order_header_id)
, constraint order_line_product_fk foreign key
(product_id) references product(product_id)
);
Note that we could model ORDER_LINE as another intersection table, with a primary key of (order_header_id, product_id) and relegate order_line_no to the status of ordinary attribute: it depends on the business rules we must represent.
This second scenario is rarer than you might think: composite primary keys are pretty rare in real life. For instance, I think the model presented in that other answer is weak. The chances are we will need to use Employee as a foreign key for a number of relationships (e.g. Manager, Assignment, Sales). Using a composite key for foreign keys is clumsy (more typing!). Furthermore, when we drill into these models we often find that one of the key columns is a natural key rather than a primary key, and so might be subject to change. Cascading changes to natural key columns in composite foreign keys is a PITN.
Hence it is common practice to use a surrogate (or synthetic) primary key, say using a sequence or identify column, and enforce the natural key with a unique constraint. The latter step is often forgotten but it is crucial to maintaining referential integrity. Given a situation in which we need to store details of Employees from several Companies, including the Companies' Employee Identifier we might have an EMPLOYEE table like this:
create table employee
( employee_id number(38,0) generated always as number
, company_id number(38,0) not null
, company_employee_id varchar2(128) not null
, name varchar2(128) not null
, constraint employee_pk primary key
(employee_id)
, constraint employee_uk unique
(company_id, company_employee_id)
, constraint employee_company_fk foreign key
(company_id) references company(company_id)
);
One situation where it is common to find composite primary keys cascaded to dependent tables is in data warehouses and other VLDBs. Here the composite key columns form part of a denormalization strategy to support Partitioning schemes and/or efficient access paths.
I have to create a database having only 2 tables student and course. There is no relation between them or say atmost 1 relation is acceptable.
Query that usually runs on it :-
"Get courses registered by a student".
So it should be quick to respond. Please tell how to implement such database?
CREATE TABLE STUDENT
(student_id INT PRIMARY KEY)
CREATE TABLE COURSE
(course_id INT PRIMARY KEY)
CREATE TABLE COURSE_REGISTRATIONS
(
student_id INT,
course_id INT,
)
In COURSE_REGISTRATIONS, the {student_id, course_id} combination is the primary key, and obviously student_id and course_id are foreign keys to their respective table.
You can query COURSE_REGISTRATIONS for the information you need.
I have an assignment where I am to create two tables within a database. The tables looks like this;
ContactPerson (ID, Forename, Surname, Email, PhoneNumber)
Company (ID, CompanyName)
Now my problem is that I have to link a ContactPerson to a specific company, but I can't have them in the same table.
I understand that I can use the join statement to show both tables in one query but I need the database to know which person is linked to which company when I implement this databse into my asp.net project.
How do I do this?
You did say "specific" company so I'm assuming you have one company per person.
Put a column in the user table called CompanyID...
ALTER TABLE ContactPerson
ADD CompanyID int
(assuming your ids are ints)
and then create the following foreign key:
ALTER TABLE [dbo].ContactPerson
ADD CONSTRAINT [FK_ContactPerson_Company]
FOREIGN KEY (CompanyID)
REFERENCES Company (ID)
Shark is correct if you want a many to many relationship.
To get all people in a company:
SELECT
*
FROM
ContactPerson
WHERE
CompanyID = x
You don't HAVE to apply the foreign key constraint, but if you don't, you can accidentally put invalid data in. All a "Constraint" does is enforce a rule for you, in other words "making sure sql knows which people are in which company" as your question suggests you need to do.
The above query would work without the Foreign key constraint, but then your database doesn't "know" about the relationship.
..and if I try and insert a person with a companyid that doesn't exist, SQL will throw an error (this is a good thing).
Since this is a one-to-many relationship, I would typically put that data into the ContactPerson table. But because you explicitly say you cannot, then just create a join table:
create table ContactPersonCompany
(
ContactPersonID int not null foreign key references ContactPerson(ID),
CompanyID int not null foreign key references Company(ID)
)
Now you have a relationship between ContactPerson and Company.
Example: select all people from a particular company
select
cp.Surname,
cp.Forename
from ContactPerson cp
inner join ContactPersonCompany cpc
on cp.ID = cpc.ContactPersonID
inner join Company c
on cpc.CompanyID = c.ID
where c.CompanyName = 'Some Company'