SQLITE - dealing with derived attributes - database

I am a CS student trying to build an app to store the grades of my dear colleagues. To do that I will be using SQLite to store the grades. In my database, there will be a table called Student (each one of my colleagues), a table Course (the courses we had), and a table Enrollment that stores the information about which course each one took.
I also want to have in the Student table two derived attributes average_grade and total_credits. As you might already imagine I will have to take this information out of the other two tables. The problem I am facing is: how should I do this?
I was thinking about using views but I sort of will be using this all the time and I don't think my app will perform well. Then I thought about materialized views but I discovered that SQLite doesn't support it, and now I am thinking about using TRIGGERS but I think I might be complicating this.
Is there any nice and clean way of doing this in SQLite? Have these values pre-computed, as a cache, and only change them when I change certain tables?
Note: I just want to freeze that I will rarely insert data into this database (only at the end of the semester or after the exam results come out).

According to your description, you have a data model like this:
If you want to update average_grade and total_credits in student table when a new row is inserted into enrollment table, you can create a trigger to do so:
create trigger if not exists tr_enrollment after insert on enrollment
for each row
begin
update student
set average_grade = c.average_grade,
total_credits = c.total_credits
from (select e.student_id as student_id,
avg(e.grade) as average_grade,
sum(c.course_credits) as total_credits
from enrollment e
join course c
on e.course_id = c.course_id
where e.student_id = NEW.student_id
group by e.student_id) as c
where student.student_id = c.student_id;
end;
However, you may need to consider if UPDATE and DELETE operations may happen on enrollment table and then create similar triggers accordingly.

Related

Database to keep track of inventory/ live stock

I am looking for help with database design for a small project I am working on.
In short what I am trying to achieve is to have say the following tables:
Paddocks
Paddock ID
Paddock Name
Paddock Size
etc.
Cattle
Herd ID
Herd Name
Number of cows
Current Paddock
Cattle_Movements
Herd Name
Current Paddock
New Paddock
Date
etc.
I was hoping to have the 'Cattle_Movements' table be like a summary of all movements of a herd of cattle. And when a herd is moved from one paddock to another it would update the 'Current Paddock' field in the 'Cattle' table.
At this stage I am trying to workout the relationships, queries and high level process that I will need to implement.
Any help will be greatly appreciated.
Start by setting up a normalized table structure. make the tables below and hook them together with the relationships tool on the ribbon under database tools-relationships. To create a relationship drag the primary key from one table to the corresponding and same named foreign key in the table that will be the many side of the relationship. In the pop up make sure to check the enforce referential integrity, cascade update, and cascade delete checkboxes.
I've highlighted the two "Many to Many Relationships" in this normalization. HerdsPaddocks is a more generic name for the CattleMovements Table. There are other possible normalized table structures, but the subtle differences are beyond the scope of this answer. When you are ready, look up table normalization and Many to Many Relationships.
Next, Close the Relationships tool, select a table from the sidebar and on the ribbon under Create hit create form. Do this for all the tables. Now we have a working database but you need to learn how to use it. So play!
Below I gave some play suggestions, but just play with everything until you figure out how to use the forms to (add, search, edit) cows, herds, and paddocks. Also learn why you should delete the primary keys from all the forms and how to replace the foreign keys like CattleType in the Cattle Table with the user friendly CattleTypeDesscription from the CattleTypes Table.
Start with the Herds table and enter some random herds. (pro tip: never add data to the table directly except when playing the error rate is too high). Then Open the herds form where you can browse and edit the herds.
Play tips: In the Table Herds HerdID is both an autonumber and a primary key. It behaves differently from the other columns. Check it out. after that delete the HerdID textbox from the form and see what happens(a good thing). How do you add herds using the Herds Form?
Moving on to playing with the Cattle form, first make sure to add a few CattleTypes to the CattleTypes table. Then at some point, try replacing the CattleTypeID in the Cattle Form with the CattleTypeDescription: https://btabdevelopment.com/how-to-change-a-text-box-to-a-combo-box-wont-work-with-data-access-page/
Also, note the Cattle Form has a subform allowing you to simultaneously assign/edit cattle assignments to herds.
Once you are comfortable adding and editing data, play with the query editor. For instance, to get how many cows are currently in Paddock holds10cattle (my dummy data).
query 1 showing the relevant data
results from query1:
Query 2 getting really close:
Query 3: which gives the number 2:
'Query 3 SQL from SQL pane of query designer
SELECT Count(Cattle.CowName) AS CountOfCowName
FROM Paddocks INNER JOIN ((Herds INNER JOIN (Cattle INNER JOIN CattleHerds ON Cattle.CattleID = CattleHerds.CattleID) ON Herds.HerdID = CattleHerds.HerdID) INNER JOIN HerdsPaddocks ON Herds.HerdID = HerdsPaddocks.HerdID) ON Paddocks.PaddockID = HerdsPaddocks.PaddockID
GROUP BY Herds.HerdName, Paddocks.PaddockName, HerdsPaddocks.HerdPaddockEndDate, HerdsPaddocks.HerdPaddockStartDate
HAVING (((Paddocks.PaddockName)="holds10cattle") AND ((HerdsPaddocks.HerdPaddockEndDate) Is Null) AND ((HerdsPaddocks.HerdPaddockStartDate)<Now()))
ORDER BY HerdsPaddocks.HerdPaddockStartDate;
Next Steps could include the specific paddock with a parameter and using the query in a report.

How do I create multiple table relationships on Access 2016?

I have a table that shows each student's details with their module choices for semester 1 under each student 1.
I want to add the semester 2 module choices as well so they can be seen on the student detail table. Is there a way to do this? When I try to set up the relationships, the student details are shown in the semester 2 options table 2, which is not what I want. I haven't done that much on access so apologies if this is a simple question or if it isn't possible...
You already created relationships. As I understand, you want to see more than one "child" table in table designer. If so, it's not possible.
If you want to select options for different semesters, create a form based on Students table and two subforms for Semester1 and 2.
Also I would recommend to change database structure. You don't need two tables for semester modules. Create just one table with additional field like SemesterNumber and place subforms, based on this table with different criterias for SemesterNumber. And add own primary key for SemesterOptions, do not use StudentID as PK, actually you have one-to-one relationship, I believe you want select more than one module for each student.
In my opinion, you should have more tables, which in end will make it much easier to query data and get reports out of it, as well it will make it easier to create forms for each table to record data.
Here is simple table structure I would do for student/class registration.
You can also link tblSemester table to tblClass, if you like to make a list of classes offered each semester and make it bit more complicated, but with this organization you will be able to get list of all classes for student, or all student for particular class or semester, and with ease add more data later.

SQL Delete vs Update

I have seen something like this asked a number of times but not quite in this configuration. I have a table that has a one to many relation.
Let’s say I have a computer table and a parts table. The user enters a generic info in the computer table then selects parts that are stored in the parts table with a relationship to the computer table of computerId. So the original write is a simple insert. Now let’s say the user select the computer again and changes the part on the pc, adds some new, removes some, and updates a few. Then the user hits save to save the changes. I run a simple update on the computer table but now the issue with the parts table.
Would it be better to delete all the records from the parts table for the computer Id and then do a clean insert of all the parts selected.
Or Run some method that would look at the existing parts in the table and where the part has been updated update the record, where the part no longer exists do a delete, and then insert the remaining parts?
Clearly the simple solution is to delete all and then insert all.
The down side of this SQL traffic, locks, and table fragmentation.
If it is small table and only few concurrent users then fine.
In a high volume environment I do the following
There is no update - that is just an ignore
- delete items gone
- ignore any items not changed
- insert new items
And you can do that in one pass two/three statements.
Or you could define a stored procedure.
Do the delete before the insert to clear space first.
You can get real fancy and use an update for delete / insert but that just gets more complex than it is worth in my mind. You would still have an insert or a delete if the item count is not the same.
delete comp_part
where compID = #compID and partID not in (....);
Insert is a little more tricky:
You can to it with a series of inserts and if you have a PK just let the insert fail
The other way is to create a #table and use it for both the delete and insert
This is only worth the hassle if you have a REALLY busy table.
It all depends upon the business model, if you would want to track the transaction than its not a good option to delete it. If you have all your old transactions with your customers than it would be beneficial for tracking purposes., Your CustomerID would be Primarykey and you can have another Unique key as PartOrderID which will be a unique value for each insert.
Hope this helps
Really you should have three tables. Product, Part, and ProductPart; the ProductPart table would store the association of "this product has these parts". As far as updating, the simplest thing would be to delete all ProductParts for a given Product and re-insert the records you want.

Most efficient way of transferring large amounts of data from one column to another?

I currently have two tables, and one has a dependency on the other that I want to remove.
Let's say the tables are Product and Employee, and there are about 800,000 rows in each table.
The Employee table has a ProductID, in which there is a ProductRefID, which I need to reference in my application. The way this is done is to join in the Product table, and reference the ProductRefID that way.
However, I now want to change this so that ProductRefID is a column on the Employee table, and then transfer every Product row's "ProductRefID" to the Employee row's "ProductRefID".
What would be the most efficient way of writing this query?
(I know it sounds stupid, but it's just an example, it's not actually what I'm trying to do specifically).
Something like this ?
alter table Employee add ProductRefID INT
update e
set ProductRefID = p.ProductRefID
from Employee e
join
Product p
on e.ProductID = p.id

HABTM-Relation : Create a relation for all other records

If i want to add a record to TABLE A, is there an efficient way to add
a record in the JOIN TABLE for many (or all) records in TABLE B?
I try to build a simple task management (in CakePHP). An user adds a task and there
will be added a connection to each other user in the same group as the
current user.
At the moment, I use the find('list')-method to retrieve the IDs and
store them in a variable. But I think if the groups grow, the PHP
cache won't handle this amount of data in a single variable.
You should look into the Cake Has-And-Belongs-To-Many (HABTM) relationships. Check the cake book. It will allow you to create a relationship between two tables, using a join table, and will automatically retrieve and save values as requested in your application.
Please note, however, that from one model you cannot (by default) filter by criteria on the related model (in this case, the model related by the join table). To do this, you will need to use the Containable behavior, which will allow you to set filter criteria on the related tables.
The one other caveat is that I don't know of a way (out of the box) to add some information about the relationship in the join table. For example, if you wanted to record (in the join table) whether the user has completed the task, you would have to write your own stuff there. I usually get around this by creating a model for the join table, which I then invoke whenever I want to retrieve data specific to the joined relationship. By doing it this way, you can also easily pull up the data from the joined tables. Anybody else have a better solution?

Resources