A non prime attribute depends on composition of a partial Partial primary key and a non prime attribute. Is the table still considered to be in 3NF - primary-key

Here is the table descriptions:
Students
SID
SNAME
1
Adams
2
Jones
3
Smith
4
Baker
Teachers
TID
TNAME
60192
Howser
45869
Langley
Classes
CID
CNAME
IS318
Database
IS301
Java
Student info:
SID
CID
TID
Grade
1
IS318
60192
A
1
IS301
45869
B
2
IS318
60192
A
3
IS318
60192
B
4
IS301
45869
A
4
IS318
60192
A
SID and CID, Composite primary key. SID,CID -> Grade and SID,TID -> Grade.
Is the table still in 3NF

Not as far as I understand it:
A database relation (e.g. a database table) is said to meet third normal form standards if all the attributes (e.g. database columns) are functionally dependent on solely the primary key.
https://en.wikipedia.org/wiki/Third_normal_form
Since your attribute is not solely dependent on the primary key, then I think not.

Related

Foreign key as primary key?

I currently have 2 tables STUDENTS and SUBJECTS. I need to create another table for ENROLLMENTS, the thing is that in that table I need to know the minimal attendance, which is both dependent on student (if he has a job it will be lower) and on subject (each subject has a base minimal attendance). Should I create another table like MINIMAL_ATTENDACE which holds the base minimal attendance of each Subject ? If so, is it good to have the primary key in that table be also the primary key from SUBJECTS ?
For example I have :
--STUDENTS--
ID NAME HIRED
1 Paul 1
--SUBJECTS--
ID NAME NUMBER_OF_TESTS M_ATTENDANCE
1 Math 2 10
--ENROLLMENTS--
ID STUDID SUBID M_ATTENDANCE
1 1 1 7 (Because Student is hired)
You can use a several constraints on a single column. Apparently, there is a many-to-many relationship between STUDENT and SUBJECT. A possible approach for implementing this (with SQL) is an "intersection" or "bridge" table is. You can use a composite PK, and foreign key constraints like this:
Demo (dbfiddle)
-- parent tables (and test data)
create table students (id primary key, name, hired)
as
select 1, 'Paul', 1 from dual union all
select 2, 'Maggie', 1 from dual union all
select 3, 'Herbert', 0 from dual ;
create table subjects (id primary key, name, number_of_tests, attendance_standard, attendance_hired)
as
select 100, 'Maths', 2, 10, 7 from dual union all
select 200, 'Biology', 3, 12, 8 from dual union all
select 300, 'Physics' 2, 10, 8 from dual ;
-- intersection
create table enrollments(
studentid number references students( id )
, subjectid number references subjects( id )
, constraint enrollments_pk primary key( studentid, subjectid )
) ;
-- test data for the "intersection" table:
-- every student needs to complete every subject
insert into enrollments
select S.id, SUB.id
from students S cross join subjects SUB ;
In the example (above), we assume that {1} the "hired" attribute belongs to a STUDENT, and {2} the different "attendance" attributes are attributes of SUBJECT.
You can now just join the 3 tables, and find the required attendance for each student using the query below.
-- Get the attendance requirements for each student & their chosen subject
select
S.name, S.hired
, SUB.name
, case
when S.hired = 1 then SUB.attendance_hired
else SUB.attendance_standard
end as attendance_required
from students S
join enrollments E on S.id = E.studentid
join subjects SUB on SUB.id = E.subjectid
;
-- output
NAME HIRED NAME ATTENDANCE_REQUIRED
Paul 1 Maths 7
Maggie 1 Maths 7
Herbert 0 Maths 10
Paul 1 Biology 8
Maggie 1 Biology 8
Herbert 0 Biology 12
Paul 1 Physics 8
Maggie 1 Physics 8
Herbert 0 Physics 10
If the "hire" status of a STUDENT can change during an academic year (or semester), you'd probably need to add some more entities (and subsequently: tables) for keeping track of each STUDENT's hire state change.
If the problem is as simple as you describe, it would be sufficient if the subject has two minimal attendences, ie. one for students with, and one for students without jobs.
You can have a primary key also a foreign key, in order to enforce the rule that the second table does not have an element which is missing from the first table. However, mixing up foreign key with primary key this way is usually a bad idea, because your rule might change. It is customary to make a field of a composite primary key also a foreign key particularly in many-to-many tables, but unless you are worried of storage space, you might want to create a foreign key on a separate field, so you will have less worries if your rule changes.
However, what you intend to store can be computed with aggregation, you do not necessarily need a separate table for that. You just group by and select min. You might also create a view if that's better, or, if changes on the main table are frequent, then you might consider the creation of a materialized view.

How to create this `check constraint`

I have two tables:
People:
Id | OrgId | Name
-----------------
1 10 Sam
2 10 Dana
3 12 Max
Id is a primary key. OrgId is foreign key to other table.
And second table Cars:
Id | Name | OrgId | PersonId
----------------------------
1 Volvo 10 1
2 BMW 10 2
Here: Id is a primary key. PersonId is a foreign key to People table. OrgId is foreign key to Organization table.
So I have Person which are attached to Organization and I have Cars which are attached to Organization and Person.
I need to guarantee that it will be impossible to attach Car from one Organization to Person from another Organization. The record:
Id | Name | OrgId | PersonId
----------------------------
1 Volvo 12 1
must be impossible because Car belongs to Organization with ID = 12, but Person belongs to Organization with ID = 10.
What is the best way to do it ?
I see two ways:
Foreign key using two fields People (Id + OrgId) <-> Cars (PersonId + OrgId).
But in this case I need to create one additional unique index on the table People ('Id+OrgId`).
Trigger on the table Cars.
What do you recommend to use in this case ?
My first reaction is to look up the organization using the person column. But, that doesn't really fit the situation -- cars are owned by organizations independently of people. So, you might need the organization, even if no person is assigned.
So, add a new key to people:
alter table people add constraint unq_people_orgid_id unique (orgid, id);
Then use this for the foreign key reference in cars:
alter table cars add constraint
foreign key (orgid, personid) references people(orgid, id);
Note that the second key is redundant. But it allows a reference that includes the organization.
I wouldn't use OrgId in your cars table, it violates normalization rules. You can use a query to get the organization information for the car using the PersonId.

How to establish a many to one relationship between 2 tables for a field

I am building an database schema for a project and I am bit stuck on this issue. I have 2 tables:
USER table:
Id Name Contact_ID
1 Arun 2
2 Barath 3
3 Charan 2
4 Dinesh 1
CONTACT table:
ID Name Phone Mail
1 Mahesh 1234 Mahesh#Yahoo.com
2 Suresh 54321 Sureh#Google.com
3 Jayesh 9876 Jayesh#Bing.com
4 Ganesh 98754 Gahesh#Safari.com
Each of the users in USER will have a contact in CONTACT.
If a user has a single contact then I can use a foreign key relationship on Contact_ID in USER and build the relationship between them.
But what if an user in the USER table has multiple contacts in the CONTACT table? I am not sure how to build the relationship between them.
Eg:
In USER for user Charan there is one contact, contact 2, but what if there is one more, contact 4?
In that case how can I build the many to one relationship?
It looks like you've got it backwards. Your CONTACT table should have a foreign key reference to USER table, rather than USER containing a foreign key reference to CONTACT. For example:
USER table
Id Name
1 Arun
2 Barath
3 Charan
4 Dinesh
CONTACT table
ID Name Phone Mail USER_ID
1 Mahesh 1234 Mahesh#Yahoo.com 1
2 Suresh 54321 Sureh#Google.com 2
3 Jayesh 9876 Jayesh#Bing.com 1
4 Ganesh 98754 Gahesh#Safari.com 3
Of course, I just used fake data for the new USER_ID column. As you can see, USER with Id 1 (Arun) has multiple contacts (IDs 1 and 3) in the CONTACT table.
In the relational model (and ER model) tables represent (business/application) relationships/associations. FKs (foreign keys) are called "relationships" by pseudo-relational (& pseudo-ER) methods.
-- user "id" has name "name" and ...
user(id, name, ...)
-- contact "id" has name "name" and ...
contact(id, name, ...)
-- user "uid" has contact "cid"
user_has_contact(uid, cid)
If user_has_contact is N:1 in uid:cid then you can replace user & user_has_contact by:
-- user "id" has ... AND user "id" has contact "cid"
user(id, name, ..., cid)
If user_has_contact is 1:N in uid:cid then you can replace contact & user_has_contact by:
-- contact "id" has ... AND user "uid" has contact "id"
contact(id, name, ..., uid)
You should use the first design for M:M. (You don't actually have to but then the joined tables exhibit problems that normalization would tell you to solve by having the separate tables.) This is called an association/junction/join/many-to-many/bridge table in methods that call FKs "relationships". But like every table it represents a relationship/association on some values. (And hence also any identified entities.) It also handles M:0-or-1 & 0-or-1:M . The other two designs can do that too using NULL.
Regardless of the cardinality of user_has_contact it is probably a good idea to keep the three separate because it is straightforward. (True ER modeling would give the two entity tables & one association table.) But you should realize that there is no need to join them.
A FK tells the DBMS that values for a list of columns in a table must appear as a CK (candidate key) elsewhere. (In SQL, a FK says they appear as a superkey, ie SQL PK (primary key) or UNIQUE NOT NULL, elsewhere.)
(Methods that call FKs "relationships" do so because FKs are associated with relationships like user_has_contact that have be joined into what becomes the referencing table. Also it is those relationships' cardinalities that are called the FKs' cardinalities. But a FK constraint just states a fact; it isn't a relationship/association.)
You need to find & follow references for information modeling & database design.

Correct Normalization for Players to Match

Each match has 14 players.
I currently have it so that I enter 14 entries into the match table like so:
matchID bookingID playerID
1 1 1
1 1 2
1 1 3
1 1 4
etc.
Would this be okay or would it be more acceptable to do it like so:
matchID bookingID playerID1 playerID2 playerID3 playerID4
1 1 1 2 3 4
No, "normalization" in this context means you would want to create multiple tables, Match, MatchPlayer, Booking, and Player that relate to one another based on their primary keys. For example:
Match table:
MatchID BookingID
---------------------
PlayerMatch table:
MatchID PlayerID
-------------------
Booking table:
BookingID
----------
Player table:
PlayerID
--------
Now the MatchID is the primary key in the Match table and it's the foreign key in the MatchPlayer table, and the PlayerID is the primary key in the Player table and it's the foreign key in the MatchPlayer table. This creates a "many to many" relationship between matches and players because there can be multiple matches in which a player can participate, and there are obviously multiple players in a given match.
Also, the BookingID is the primary key in the Booking table and it's the foreign key in the Match table, and in this case, there is a "one to many" relationship between bookings and matches because there can be multiple matches at each booking.
This approach allows you, for example, to have one record per player so you can have additional information about a player without repeating that information unnecessarily in the Match table, like first name, last name, age, gender, etc. Similarly, it allows you to have one record that holds information about a booking, like date, venue name, etc.
Given your current example, normalization would seem to be unnecessary since you don't have any additional information about players and bookings, but it seems like your schema could quickly expand to involve more information.

Weak Entity containing a foreign key as a primary key

I have created a table called STUDENT which consists of Unique ID as the PRIMARY KEY along with other related attributes like Name, Addr, Gender etc....
Since I don't want to increase the table size of the STUDENT, I created a weak entity called ACADEMIC RECORDS which stores the previous Academic Records of the student.But in this table i have only created a PRIMARY KEY Unique ID which references the Unique ID of the student. and there is no other attribute in conjunction with Unique ID in the weak entity ACADEMIC RECORD Table.
As I came across the definition OF A WEAK ENTITY which define its primary key as a combination of weak entity's attribute and the owner's table's primary key(in this case STUDENT)
Is my method of creating a foreign key as the only primary key in the table ACADEMIC RECORD correct??
STUDENT Table
**UID** NAME GENDER ADDRESS PHNO.
ACADEMIC RECORD Table
**UID** HighschoolMarks GradSchoolMarks
There's nothing necessarily wrong with having a primary key that's also entirely a foreign key. It's a common way of implementing something like ‘base classes’, where an entity has a row in a base table, and may have a row in one or more extension tables (one to one-or-zero relationship).
I'm not sure it's the most appropriate schema for what you're doing though. If there really is an exactly one-to-one relationship between academic_records and students, it looks like they are part of the same entity to me.
In which case from a normalisation point of view the record columns should be part of the main students table. Maybe there's an efficiency reason to denormalise, but “I don't want to increase the table size” is not normally an adequate reason. Databases can cope with big tables.
I'm not completely clear on what you are asking, but it sounds like you are using the correct method.
Your STUDENT table requires a primary key to provide a unique reference for each row.
Your ACADEMIC_RECORD table also requires a primary key to provide a unique reference for each row.
Each student may have zero or more academic records, and you want to identify the student to which each academic record belongs. You do this by adding a column in the ACADEMIC_RECORD table which contains the id (the primary key) of the student:
STUDENT ACADEMIC_RECORD
id
id <-------> student_id
name high_school_marks
gender grade_school_marks
address
phone_no
Assume you have three students: Alice, Bob and Dave. Alice and Dave have three academic records, and Bob has two. Your tables would look something like this (I've omitted some columns to make things clearer):
STUDENT
id name
1 Alice
2 Bob
3 Dave
ACADEMIC_RECORD
id student_id
1 1
2 1
3 1
4 2
5 2
6 3
7 3
8 3