How do I keep one column consistently updated? - mysql

I have a faculty table, and each faculty has a certain number of students under him/her. So there is a 'current' column, which is the number of students currently under them.
However, I don't want to ++ and -- every time I switch a student to another faculty. Is there a way to keep the column updated with a query that uses count()? I find it is easier and more accurate to use the query 'select count() from student where advisor = 2' for example that using my current column.

To do this, use a view:
CREATE VIEW studentCount AS
SELECT
profID,
profName,
whatever,
(SELECT COUNT(*)
FROM studentTable
WHERE studentTable.profID=profTable.profID
) AS studentCount
FROM profTable;
Obviously, this needs to be massaged a little to fit your schema, but essentially, setup your view to have all the columns of the table with the faculty info and add a column at the end that counts the number you want in it.

Triggers could be a solution to you problem?
http://dev.mysql.com/doc/refman/5.5/en/triggers.html
You could create a trigger that automaticly updates your faculty table every time a student switch faculty.

Related

keep track of presence

I am trying to find a way how to keep track of students lessons presence (and absence). The main problem is that they pay in advance a series of 10 or 30 lessons, and once is done the can pay a new serie.
What is the best solution of doing that?
I will have two tables that looks sort of like that
presence
id
user_id
lesson_id
absence
id
user_id
lesson_id
reason
I was thinking on both tables to add a boolean column that will be true when the series is done (sort of bookmark). Then when I access the database my query will, for every user_id, count how many records there are after the last true value (if any).
Doesn't sound like a good strategy to me but I can't find another way.
Firstly, you need a User_Lesson_Series table:
User_Lesson_Series
id
user_id
number_of_lessons_paid_for
payment_date
number_of_lessons_remaining
Secondly, the suggestion made by P.Salmon of having an Attendance table (rather than a Presence table and an Absence table) is a good one:
Attendance
id
lesson_id
user_lesson_series_id
absence_flag
absence_reason
When inserting a record into User_Lesson_Series for the first time, set number_of_lessons_remaining to the same value as number_of_lessons_paid_for.
Every time you record a student's attendance (or non-attendance) in the Attendance table, you should also update that record's parent row in the User_Lesson_Series table, decrementing number_of_lessons_remaining by 1.
If a User_Lesson_Series record has number_of_lessons_remaining = 0, then you should not permit any more Attendance records to be written out for that user_lesson_series_id. Instead, you should require a new user lesson series to be paid for, necessitating a new User_Lesson_Series record to be generated.
Subsequent Attendance records will have the user_lesson_series_id of that new User_Lesson_Series.
I'd probably make this one student_lesson table:
student_lesson (student_id, lesson_id, status_id, absence_reason)
plus a status table for the statuses Open, Attended, Absent.
Once a student pays for the next n lessons, you create n rows in the student_lesson table. And when a lesson has passed, you update the status to either Attended or Absent.
With an index on student_id and status_id you can quickly see how many Open lessons a student still has.

Complex mysql update based on two fields and 'most' criteria?

update employee as a
set a.sup_role=(
select b.job_role from employee as b
where b.supervisorid=a.employeeid
group by b.job_role
order by count(b.job_role) desc
limit 1
)
where a.job_role='MAN1';
OK I have a table of all of our employees - around 100K.
All of our users have job roles that I built based on their employee.job_title. So based on 4K+ job_titles I knock that down to about 40 job_roles. This is so we can assign things in our CMS based on employee.job_roles. This has been working good but the problem is with the managers. The managers get some generic corporate job_title that we role into a generic job_role.
What you see above is code that I use to kind of do what I need to do - find out what job_role a supervisor based on what "most of their employees do". This outputs the correct sup_role but there are several things wrong with my code:
based on my syntax it won't let me update the employee table directly. I have have to update an employee "helper" table and fill in later.
So it is parsing through for the job_role "MAN1". First I don't want to update this to add new manager job roles. Also this doesn't account for my company doing ad hoc things like a manager just have a regular job title or different NULL fields.
And then the last part is that this code is taking 6 minutes to go through. Luckily I run this as a batch job but I am afraid it might cause crashes.
So I have the following table -
employee
with applicable fields
employeeid
supervisorid
job_title
job_role
sup_role
So below is my last attempt. It just runs and never outputs anything. I am wondering if I need to create a helper table to grab the DISTINCT supervisorid's since one employee could be many people's supervisor.
update employee as a
set a.sup_role=(
select b.job_role from employee as b
where b.supervisorid=a.employeeid
group by b.job_role
order by count(b.job_role) desc
limit 1
)
WHERE a.uid IN (select DISTINCT employee.supervisorid
from employee
where employee.supervisorid is not null
);

Pulling different records from multiple tables as one transaction history list

I am working on an employee management/reward system and need to be able to show a single "transaction history" page that shows in chronological order the different events that the employee has experienced in one list. (Sort of like how in facebook you can goto your history/action section and see a chronological list of all the stuff that you have done and affects you, even though they are unrelated to eachother and just have you as a common user)
I have different tables for the different events, each table has an employee_id key and an "occured" timestamp, some table examples:
bonuses
customers
raise
complaints
feedback
So whenever an event occurs (ie a new customer is assigned to the employee, or the employee gets a complaint or raise) a new row is added to the appropriate table with the employee ID it affects and a timestamp of when it occured.
I need a single query to pull all records (upto 50 for example) that include the employee and return a history view of that employee. The field names are different in each table (ie the bonus includes an amount with a note, the customer includes customer info etc).
I need the output to be a summary view using column names such as:
event_type = (new customer, bonus, feedback etc)
date
title (a brief worded title of the type of event, specified in sql based on the table its referencing)
description (verbiage about the action, such as if its event_type bonus display the bonus amount here, if its a complain show the first 50 characters of the complaint message or the ID of the user that filed the complaint from the complaints table. All done in SQL using if statements and building the value of this field output based on which table it comes from. Such as if its from the customers table IF current_table=customers description='A customer was assigned to you by'.customers.assigner_id).
Ideally,
Is there any way to do this?
Another option I have considered, is I could do 5-6 different queries pulling the records each from their own table, then use a mysql command to "mesh/interleave" the results from all the queries into one list by chronological order. That would be acceptable too
You could use a UNION query to merge all the information together and use the ORDER BY clause to order the actions chronologically. Each query must have the same number of fields. Your ORDER BY clause should be last.
The examples below assume you have a field called customer_name in the customers table and bonus_amount in the bonuses table.
It would look something like this:
SELECT 'New Customer' as event_type, date,
'New customer was assigned' as title,
CONCAT('New Customer: ', customer_name, ' was assigned') as description
FROM customers
WHERE employee_id = 1
UNION
SELECT 'Bonus' as event_type, date,
'Received a bonue' as title,
CONCAT('Received a bonus of $', FORMAT(bonus_amount, 2), '.') as description
FROM bonuses
WHERE employee_id = 1
UNION
...
ORDER BY date DESC;

Trigger for new table inserts

I have 2 tables, Organisation and State(where it is). Each Organisation has a state. I would now like to implement a Integer column for the table State which keeps tracks of how many organisations are in it. Kinda like whenever a new organisation is inserted into Organisations table, update integer column in corresponding State table where org.state_id = state_id.
Is this possible using triggers?
Rather than keeping track of a computed column, it is often preferable to just calculate what you want on demand. So if you have these two tables:
organization(id, name, state_id)
state(id, name)
A query such as the following gets the counts:
SELECT s.name, COUNT(*) AS organization_count
FROM state s JOIN organization o ON (s.id = o.state_id)
GROUP BY s.name
This avoids integrity issues. If you are dealing with hundreds of thousands of records or operating in a reporting environment, then you might want to consider computing the info.
I agree with Glenn's answer that, all things being equal, on-demand is a better solution, but the answer is that, yes, it can be done with a trigger. Very easily.
CREATE TRIGGER organization_trigger_insert AFTER INSERT ON organization
FOR EACH ROW BEGIN
UPDATE state SET total = total + 1 WHERE NEW.state_id = state_id;
END;
CREATE TRIGGER organization_trigger_delete BEFORE DELETE ON organization
FOR EACH ROW BEGIN
UPDATE state SET total = total - 1 WHERE OLD.state_id = state_id;
END;
Demo

What is the best way to count rows in a mySQL complex table

I have a table with the following fields (for example);
id, reference, customerId.
Now, I often want to log an enquiry for a customer.. BUT, in some cases, I need to filter the enquiry based on the customers country... which is in the customer table..
id, Name, Country..for example
At the moment, my application shows 15 enquiries per page and I am SELECTing all enquiries, and for each one, checking the country field in customerTable based on the customerId to filter the country. I would also count the number of enquiries this way to find out the total number of enquiries and be able to display the page (Page 1 of 4).
As the database is growing, I am starting to notice a bit of lag, and I think my methodology is a bit flawed!
My first guess at how this should be done, is I can add the country to the enquiryTable. Problem solved, but does anyone else have a suggestion as to how this might be done? Because I don't like the idea of having to update each enquiry every time the country of a contact is changed.
Thanks in advance!
It looks to me like this data should be spread over 3 tables
customers
enquiries
countries
Then by using joins you can bring out the customer and country data and filter by either. Something like.....
SELECT
enquiries.enquiryid,
enquiries.enquiredetails,
customers.customerid,
customers.reference,
customers.countryid,
countries.name AS countryname
FROM
enquiries
INNER JOIN customers ON enquiries.customerid = customers.customerid
INNER JOIN countries ON customers.countryid = countries.countryid
WHERE countries.name='United Kingdom'
You should definitely be only touching the database once to do this.
Depending on how you are accessing your data you may be able to get a row count without issuing a second COUNT(*) query. You havent mentioned what programming language or data access strategy you have so difficult to be more helpful with the count. If you have no easy way of determining row count from within the data access layer of your code then you could use a stored procedure with an output parameter to give you the row count without making two round trips to the database. It all depends on your architecture, data access strategy and how close you are to your database.