Existing table design change in SQL Server - sql

My existing table structure is below:
Students table and columns are below:
Year
Student_Id
Subject_Type_Id
Quarter
Complete_DTTM
Column1
Existing data like below:
Students:
Year Student_Id Quarter Subject_Type_Id Complete_DTTM Column1
---------------------------------------------------------------------------------------
2006 1 1 1 Null x
2006 1 2 1 10/2/2006 xyz
2006 1 2 2 10/30/2006 abc
2006 1 2 3 11/20/2006 def
One student can take multiple subjects by saving each subject separately by picking from DropDownList.
Now new requirement is one student can take multiple subjects by selecting from Checkboxes and provide data for Column1 and Complete_DTTM and save.
The difference between old and new requirement is how user selecting subject types, in old from Drop down list, able to pick one subject only, Column1 and Complete_DTTM are different for each subject.
With the new requirement, they can pick multiple subjects from check boxes for a student and column1 and Complete_DTTM is same for all subjects.
NEW data going to be like below:
Year Student_Id Quarter Subject_Type_Id Complete_DTTM Column1
--------------------------------------------------------------------------
2015 1 1 1, 2, 3, 4 12/31/2015 abcdef
2015 1 2 1, 2, 3, 4, 5 1/1/2016 xyz
How do I change ‘Students’ table (I can add new table) to support multiple subject Ids and also needs to support old data (shown above for year 2006)?
Thanks in advance

You need to make a table that will house just the student data. Then you will need to make a table that will house Subject Type data. The a table to link them together.
CREATE TABLE Student (ID INT NOT NULL PRIMARY KEY, NAME VARCHAR(50) NOT NULL,n...)
Create Table for subject
CREATE TABLE Subject (ID INT NOT NULL PRIMARY KEY, Subject_Name VARCHAR(50)NOT NULL,n...)
Then You will need a table to link these two together.
CREATE TABLE Student_Suject_Link (Student_ID INT NOT NULL, SUBJECT_ID INT NOT NULL)
The link table will need to have a foreign key realtionship to the Student table and the Subject table. Student_ID needs to be a foreign key to the ID column in the student table and same for the subject table. The SUbject_ID needs to be a foreign key to the ID in the Subject table. This should satisfy 3rd normal form. And if you need to grab data it is easy enough to join tables to get what you need. I relaize it seems to create more work but it is infinately easier to manage that adding lists to tables. You can of course add other fields you deem necessary into the table it is just necessary to have the ID's to relate on. Hope this helps.

You now have a one to many relationship and you need a child table for the many part of the relationship. Do not ever store data in a comma delimited list. This is a way to totally break your performance when you want to find data int hose tables. It is just bad deign. You need to normalize those tables and I am sure that this is why you have been given this particular exercise.

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.

Storing multiple values in a single column

I have two columns in my table: [Employee_id, Employee_phno].
Employee_id: primary key, data type = int
Employee_phno: allows null, data type = int
Now, how can I insert two phone numbers in the same employee_id?
For example:
employee_id employee_phno()
1 xxxxxxxxx
yyyyyyyyyy
For me, if you want multiple data for column Employee_phno better make another table for Employee_phno. In your second table, set a foreign key as relation for your first table.
Example:
1st table
Employee_id
1
2
3
2nd table
Employee_id Employee_phno
1 1234
2 1512
2 4523
Here you can see the employee with id = 2 has multiple Employee_phno
It is never possible to insert data in such way in single table.
If Employee_id is primary key then you can have only 1 record for an employee.Since you have only one field for Employee_phno,it's not possible to store 2 phone numbers for the same employee.
For doing so, you will have to do any one of the following:
1.Add another column in the data as Employee_Alternate_phno and if all the employees won't have 2 numbers you can make this column allow NULLs.
2.Create another mapping table say EmployeeNumbers where you will have EmployeeId as Foreign key and then the numbers field. Anytime if you want the 2 Employee_phno you can do a join on the mapping table and retrieve the values.

Can a table title be a Primary Key?

I'm trying to retrofit some tables to an existing database. The existing database has equipment numbers and I'm trying to add in tables with more information on that equipment. Ideally, I'd like to make the table titles the ID numbers and set those as the PK of that table, making the ID numbers in the equipment list the FK.
Is it possible to set the table title as the PK? Here's an example of one of the tables, and I'd like to make "E0111" the PK.
CREATE TABLE E0111(
EQUIPMENT Varchar(200),
MAINTENANCE varchar(200),
CYCLE varchar(200)
);
No you can't do this because the primary key needs to be unique for every row of your table. If you "could" use the table name as the primary key it would be the same for every row.
You should use a unique column in your table as the primary key.
Also, I have no idea how you could achieve this with SQLite or any DBMS.
First thing before I even get anywhere near answering the question about the table names being primary keys, we need to take a step back.
You should NOT have a table for each piece of equipment.
You need an Equipment table, that will store all of your pieces of Equipment together. I assume you have that already in the existing database.
Hopefully it is keyed with a Unique Identifier AND an Equipment Number. The reason for having a separate Unique Identifier, is that your database server uses this for referential integrity and performance - this is not a value that you should show or use anywhere other than inside the database and between your database and whatever application you are using to modify the database. It should not typically be shown to the user.
The Equipment Number is the one you are familiar with (ie 'E0111'), because this is shown to the User and marked on reports etc. The two have different purposes and needs, so should not be combined into a single value.
I will take a stab at what your Equipment table may look like:
EquipmentId int -- database Id - used for primary key
EquipmentName Varchar(200) -- human readable
EquipmentDescription Text
PurchaseDate DateTime
SerialNumber VarChar(50)
Model Varchar(200)
etc..
To then add the Maintenance Cycle table as you propose above it would look like:
MaintenanceId int -- database Id - used for primary key this time for the maintenance table.
EquipmentId int -- foreign key - references the equipment table
MaintenanceType Varchar(200)
DatePerformed DateTime
MaintenanceResults VarChar(200)
NextMaintenanceDate DateTime
To get the results about the Maintenance Cycle for all equipment, you then JOIN the tables on the 2 EquipmentIds, ie
SELECT EquipmentName, EquipmentDescription, SerialNumber, MaintenanceType DatePerformed
FROM Equipment
JOIN MaintenanceCycle ON Equipment.EquipmentId = Maintenance.EquipmentId
WHERE EquipmentName = 'E0111'
You cannot make the name of the table a primary key.
All primary keys should be unique and a table column not table name. This is the general rule of thumb for a priamry key. There are plenty of resources on the internet about Primary keys.
Here are just afew:
http://www.w3schools.com/sql/sql_primarykey.asp
http://database-programmer.blogspot.co.uk/2008/01/database-skills-sane-approach-to.html
The name of a table should be descriptive of what is hold within it. See that data table as a drawer where you shall label what it contains.
In my humble point of view, the ID of an equipement shall only be labeled as-is on the equipement in question. Otherwise, in your database, it shall be the table Equipments that prevails with the ID of each piece of equipment you have.
Then, if you have other equipment-related information to save, add another table with the kind of information it shall contains, with the ID of the related equipment for which this information is saved.
For example, let's say we hold a maintenance schedule over your equipment.
Equipments
-----------------------------------------------------
Id | Description | Location | Brand | Model
-----------------------------------------------------
1 | Printer/Copier| 1st Floor | HP | PSC1000
Maintenances
---------------------------------------------------------
Id | Description | Date | EquipmentId | EmployeeId
---------------------------------------------------------
Note that the EmployeeId column shall be there only if one requires to know who did what maintenance and when, for instance.
MaintenanceCycles
--------------------------------------------
Id | Code | Description | EquipementId
--------------------------------------------
1 | M | Monthly | 1
This way, every equipment can have its cycle, and even multiple cycles per equipment if required. This lets you the flexibility that you need for further changes.

Insert data from excel sheet into linked access tables

I have multiple(About 9) access tables with One to Many and Many to one relationships(All tables are linked someway, There is a master table with has one to many and many to one relationship with all the tables). I want to insert data into three tables from an excel sheet.
Excel sheet provided has data for only three of the linked tables. How can I best approach this? How complicated insert query I am looking at here?
Any suggestions much much appreciated.
EDIT:
Here is my table structure:
Subject
SubjectID (Autonumber) Primary Key
MasterID (Number) Foreign Key
Description (Text)
Master
MasterID (Autonumber) Primary Key
StatusID (Number) Foreign Key
StudentID (Text)
Description (Text)
Status
StatusID (Autonumber) Primary Key
Description (Text)
Table Relationships:
Master (One) --> (Many) Subject
Status (One) --> (Many) Master
Data from Excel:
StudentID Subject Status
JP121 Math Active
SP223 Bio Active
JK111 Chem In Suspense
LS433 Bio In Active
NP833 Math In Active
SS777 Chem Active
BK299 Bio In Suspense
Depending on yout table structure, this the process i would recommend
1.) Build Status table by selecting all Unique STATUS from Excel.
2.) Build the Subject Table by selecting all Unique Subjects from Excel.
3.) Once these tables are populated, you can proceed to build your master table. For every student row in the excel, fetch the statusID from status table and subjectID from subject table
Does this make sense?
Regarding Status table My understanding is that you intend to populate Status ID something like this
StatusID | Description
---------|------------
1 | Active
2 | InActive
3 | In Suspense
also to add, Subject table does not require MasterID column. Instead you can have SubjectID column in Master table

SQL - Properties Structure

What is the best way to setup this table structure.
I have 3 tables, one table we'll call fruit and the other two tables are properties of that fruit so fruit_detailed and fruit_basic.
fruit
id | isDetailed
fruit_detailed
id | price | color | source | weight | fruitid?
fruit_basic
id | value | fruitid?
So what I want to do is have a property in fruit called isDetailed and if true, fill the fruit_detailed table with properties like color, weight, source, etc (multiple column). If its false then store in fruit_basic table with properties written in a single row.
Storage sounds quite basic but if I want to select a fruit and get its properties, how can I determine which table to join? I could use and IF statement on the isDetailed property and then join like that but then you have two different types of properties coming back
How would you create the tables or do the join to get the properties? Am I missing something?
Personally, I see no need to split the basic and detailed attributes out into separate tables. I think they can/should all be columns of the main fruit table.
I would probably model this like so:
CREATE TABLE Fruits (
fruit_id INT NOT NULL,
CONSTRAINT PK_Fruit PRIMARY KEY CLUSTERED (fruit_id)
)
CREATE TABLE Fruit_Details (
fruit_id INT NOT NULL,
price MONEY NOT NULL,
color VARCHAR(20) NOT NULL,
source VARCHAR(20) NOT NULL,
weight DECIMAL(10, 4) NOT NULL,
CONSTRAINT PK_Fruit_Detail PRIMARY KEY CLUSTERED (fruit_id),
CONSTRAINT FK_Fruit_Detail_Fruit FOREIGN KEY (fruit_id) REFERENCES Fruit (fruit_id)
)
I had to guess on appropriate data types for some of the columns. I'm also not sure exactly what the "value" column is in your Fruit_Basic table, so I've left that out for now.
Don't bother putting a bunch of IDs out there simply for the sake of having an ID column on every table. The Fruits->Fruit_Details relationship is a one-to-zero-or-one relationship. In other words, you can have at most one Fruit_Details row for each Fruits row. In some cases you might have no row in Fruit_Details for a particular row in Fruits.
When you're querying you can simply OUTER JOIN from the Fruits table to the Fruit_Details table. If you get back a NULL value for Fruit_Details.fruit_id then you know that the fruit doesn't have any details. You can always include the Fruit_Details columns, they'll just be NULL if the row doesn't exist. That way you can always have homogeneous resultsets. As you've discovered, otherwise you end up having to worry about different column lists coming back depending on the row in question, which will lead to tons of headaches.
If you want to include an "isDetailed" column then you can just use this:
CASE WHEN Fruit_Details.fruit_id IS NULL THEN 0 ELSE 1 END AS isDetailed
This approach also has an advantage over putting all of the columns in one table because it lowers the number of NULL columns in your database and depending on your data can substantially decrease storage requirements and improve performance.
I'm not sure why you would need to store a basic or detailed list of the fruit in different tables. You should just have 1 table and then leave some of the fields null if the information doesn't exist.
Assuming that value from fruit_basic is the same as price from fruit_detailed, you'd have something like this.
fruit
id | detail_id (fk to fruit_detailed table)
fruit_details
detail_id | price | color | source | weight