Update Calculated [Field] Base on the status of a Separate Table - ms-access

I need to change the value of a Calculated FIELD depending on the results from a separate table.
I made up a small Fake DB(attached) to highlight my problem..
When the Database is open I want to be able to show on the first screen if ALL training is up to date for each employee, by changing the value of the "Calculated Field".
I have 5 Employees.
Each Employees must do 5(or more) training's.
All Training's must NOT be expired.
If a single training is expired Change Calculated Field Value to "NO GOOD"
If ALL training is NOT expired Change Calculated Field Value to "ALL GOOD"
I have no Idea on how to approach this scenario. Do I need to create a separate "Temp Table" to store this value?
Database found HERE: http://1drv.ms/1tX7L9M
I can't link pictures or more than 2 links yet so please look at these:
http://1drv.ms/1tXhr45
Here is my query.
SELECT Training.ID, Training.EmployeeID, Employees.Name, Training.TrainingID, Training.TrainingDate, TrainingList.Frequency, DateAdd("m",[frequency],[TrainingDate]) AS DueDate
FROM Employees INNER JOIN (Training INNER JOIN TrainingList ON Training.TrainingID = TrainingList.TrainingID) ON Employees.EmployeeID = Training.EmployeeID;
I need to check that all training for each Employee is current. If it is then I need to show this by changing the value from my first form.. The record source of the first form is like this:
SELECT DISTINCTROW Employees.ID, Employees.Name, Employees.EmployeeID, "Help With This Field" AS TrainingStatus
FROM Employees;
The Purpose of this is to make my life easier and be able to see at a glance which employees need to do recurrent training and which are up to date.. I still can't visualized how this can be done.. I am a (Google is my teacher kind of access user :( )

You have a query which computes the DueDate for all training records. Use it as the data source for another query in which you restrict the results to only those records whose DueDate has not already passed.
SELECT tq.*
FROM [Training Query] AS tq
WHERE (((tq.DueDate)>=Date()));
If that query returns the correct records --- only those trainings which have not expired --- reuse its WHERE clause in a GROUP BY query where you count up the number of unexpired trainings per each employee.
SELECT tq.EmployeeID, Count(tq.TrainingID) AS CountOfTrainingID
FROM [Training Query] AS tq
WHERE (((tq.DueDate)>=Date()))
GROUP BY tq.EmployeeID;
If that query also produces sane results, you can use an IIf expression to return "ALL GOOD" when CountOfTrainingID >= 5 and "NO GOOD" when it's < 5.
SELECT
sub.EmployeeID,
sub.CountOfTrainingID,
IIf(
sub.CountOfTrainingID >= 5,
'ALL GOOD',
'NO GOOD'
) AS TrainingStatus
FROM
(
SELECT tq.EmployeeID, Count(tq.TrainingID) AS CountOfTrainingID
FROM [Training Query] AS tq
WHERE (((tq.DueDate)>=Date()))
GROUP BY tq.EmployeeID
) AS sub;
That should get you most of the way to your goal. You would still need to join in the Employees table to get their names.
There may be other issues which you still need to address:
If an employee has not yet completed any trainings, or all his trainings have expired, should his name appear in the query (and form based on that query)?
Is your criteria based on 5 or more different trainings? For example, if an employee completed only the same training 5 times in the past month, should his TrainingStatus be good or no good?

Related

MS ACCESS - Finding field for most recent record

Apologies for title, I am not sure how to phrase it.
I currently have two tables "ASSETS" and "LOANS"
ASSETS contains a straightforward list of equipment
It has a field "AssetID" which has a One-To-Many relationship with a field in LOANS called "LoanAssetID"
Each piece of equipment can have many loans. It can be loaned to one person, then returned, then loaned to another. There is a field in "LOANS" named "ReturnDate" in which people record the date that a piece of equipment was returned. There is also a field called "StartDate".
A piece of equipment can said to be currently 'on loan' if the most recent record (that with the most recent start date) has no return date.
However, I am not clear enough in my query writing to complete this. I need to find the most recent record as for any asset, there may be multiple return dates, but these may not always correspond to the most recent loan.
Ideally, I would then like this to calculate a field to mark the equipment as 'on loan' 'available' etc.
Thanks for any help in advance
So far I have tried a Max Query, but, probably due to me misunderstanding queries, I am confused as to why it returns more than one result.
So, currently I have tried
SELECT Max(tbl_Loans.[Start Date]) AS [MaxOfStart Date],tbl_Loans [Return Date], tbl_Loans.LoanAssetID
FROM tbl_Loans
GROUP BY tbl_Loans.[Return Date], tbl_Loans.LoanAssetID
HAVING (((tbl_Loans.[Return Date]) Is Null));
However, what I would like is the most recent value only for any given LoanAssetID; what I get is more than one field for each given LoanAssetID where more than one result exists.
Thank you for your help
The query is grouping by return date, which I don't believe you want. Try:
SELECT Max(tbl_Loans.[Start Date]) AS [MaxOfStart Date],tbl_Loans.[Return Date], tbl_Loans.LoanAssetID
FROM tbl_Loans
GROUP BY tbl_Loans.LoanAssetID
HAVING tbl_Loans.[Return Date] Is Null;
Alternatively, if your system is robust enough to assume that any null return date will correspond with the most recent loan since an asset that has yet to be returned could not be lent to a different individual, you could just search the table for Null return dates:
SELECT tbl_Loans.LoanAssetID
FROM tbl_Loans
GROUP BY tbl_Loans.LoanAssetID
HAVING tbl_Loans.[Return Date] Is Null

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;

Adding a query (new join) to an existing join

So I have three databases (all on one server) that I need to join tables on. Essentially I do a join across two tables to determine the identification of particular users who do a certain thing after a certain date. It works fine:
SELECT a.THING, a.ANOTHERTHING, b.IDENTIFICATION, b.RELEVANTDATE
FROM FIRSTDATABASE.TABLE a
JOIN SECONDDATABASE.TABLE b
ON a.THING = b.THING
WHERE ANOTHERTHING = '----' AND IDENTIFICATION <> 'NULL'
AND b.RELEVANTDATE > date('YYYY-MM-DD')
At present I'm also running a second query by its lonesome - this is one table, on a third database - to get all users with a certain amount of an item. It also works:
SELECT ITEM, AMOUNT, IDENTIFICATION
FROM TABLE
WHERE ITEM = '----' AND AMOUNT > '0' AND IDENTIFICATION <> 'NULL'
GROUP BY AMOUNT
I then, using the first table as my guide, use VLOOKUP so I can get the AMOUNT generated in the second query for each and every user IDENTIFICATION meeting the criteria after a certain date AND who did a certain thing, from the first query.
My question is, how would I join these two into one large query?

JOINing tables while ignoring duplicates

So, let's say I have a hash/relational table that connects users, teams a user can join, and challenges in which teams participate (teams_users_challenges), as well as a table that stores entered data for all users in a given challenge (entry_data). I want to get the average scores for each user in the challenge (the average value per day in a given week). However, there is a chance that a user will somehow join more than one team erroneously (which shouldn't happen, but does on occasion). Here is the SQL query below that gets a particular user's score:
SELECT tuc.user_id, SUM(ed.data_value) / 7 as value
FROM teams_users_challenges tuc
LEFT JOIN entry_data ed ON (
tuc.user_id = ed.user_id AND
ed.entry_date BETWEEN '2013-09-16' AND '2013-09-22'
)
WHERE tuc.challenge_id = ___
AND tuc.user_id = ___
If a user has mistakenly joined more than one team, (s)he would have more than one entry in teams_users_challenges, which would essentially duplicate the data retrieved. So if a user is on 3 different teams for the same challenge, (s)he would have 3 entries in teams_users_challenges, which would multiply their average value by 3, thanks to the LEFT JOIN that automatically takes in all records, and not just one.
I've tried using GROUP BY, but that doesn't seem to restrict the data to only one instances within teams_users_challenges. Does anybody have any ideas as to how I could restrict the query to only take in one record within teams_users_challenges?
ADDENDUM: The columns within teams_users_challenges are team_id, user_id, and challenge_id.
If this is a new empty table, you can express your 'business rule' that a user should only join one team per challenge as a unique constraint in SQL:
alter table teams_users_challenges
add constraint oneUserPerTeamPerChallenge
unique (
user_id
, team_id
, challenge_id
);
If you can't change the table, you'll need to group by user and team and pick a single challenge from each group in the query result. Maybe pick just the latest challenge.
I can't test it, but if you can't clean up the data as Yawar suggested, try:
SELECT tuc.user_id, SUM(ed.data_value) / 7 as value
FROM entry_data ed
LEFT JOIN
(
select tuc.user_id, tuc.challenge_id from teams_users_challenges tuc group by tuc.user_id, tuc.challenge_id
) AS SINGLE_TEAM
ON SINGLE_TEAM.user_id = ed.user_id AND
ed.entry_date BETWEEN '2013-09-16' AND '2013-09-22'
WHERE tuc.challenge_id = ___
AND tuc.user_id = ___