Pulling different records from multiple tables as one transaction history list - mysql

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;

Related

Find duplicate between two dates with same Employee ID and same child name in vba access

I have a Form name frmCEA1 and a Table named tabsubCEA. Field names are:
E_ID (which is Employee ID, number field)
FY (which is Financial Year, String i.e. 2014-15)
FChildPrFr ( Which is Claim start Date, Date ( dd-mmm-yy format))
FChildPrupto ( Which is Claim end Date, Date(dd-mmm-yy format))
There are also
four fields in table (tabSubCEA)
EID (which is Employee ID, number field),
FY (which is Financial Year, String i.e. 2014-15),
PeriodFrom ( Which is Claim start Date, Date ( dd-mmm-yy format)),
Periodtill ( Which is Claim end Date, Date(dd-mmm-yy format)).
An employee can process claim single times in a financial Year for single child and he/she can claim for maximum two child. He/She can claim separate for both child or can claim as combined. He/She can also claim for previous financial Year.
I processed claim for an employee for single child in Fin.Year 2014-15 now employee is going to claim his/her second child for same financial year and I processed it successfully.
I want to know that How can my form(frmCEA1) prevent me using (messagebox) if i goes to process claim for same information i.e. same E_ID, First or Second Child with same claim between starting and ending Period.
I tried so much but could not success. Kindly help...
This doesn't necessarily have to be done in VBA, but that is an option. Either way, a query needs to be run to extract the number of records that match a given situation.
When an employee is being processed, run a query against that employee ID within your tabSubCEA table to find the number of records that exist for the desired financial year. However, instead of returning the actual record data, just return the COUNT of the records. If I'm understanding your situation correctly, whenever the COUNT exceeds two, then you don't want to process the employee. The easiest way would be to disable whatever "submit" button on the form.
Your query, whether a created query that references fields on the form, or via VBA would look something like this:
SELECT
COUNT(*)
FROM
tabSubCEA
WHERE
EID = '<employee id here>' AND
FY = '<fiscal year here>' AND
PeriodFrom > '<application date here>' AND
Periodtill > '<application date here>'
This will count the number of records that the employee in question has successfully filed during the desired fiscal year with an active claim period.
Basically, what you're trying to extract from the system is a count of the number of records that meet a specific criteria to this situation. You're going to want something similar to this to validate the number of claims an employee is making.

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

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?

how to design the tables for customer orders and bills

Am designing a database schema (orders and bills) for a hotel system.
The attached image shows the tables in the database schema.
The question is how do I design the bills table, so that I can calculate the customer bill from orders the customer has made?
My assumption is that a bill is calculated after the order is made, and not the other way round, e.g. creating a bill before we make an order.
I am considering this answer however it does not solve my problem, since I want to calculate bills from customer orders.
The red rectangle shows the relationship between the orders and bill table this is where am stuck, I don't know how to design the tables.
Some language standardization first:
By Order you mean Sales Order, OrderDetails are called Line Items, and a Bill is usually called a Sales Invoice.
An sales invoice is a request for payment. You issue one when you think someone owes you money.
Depending on the terms of the sales order, someone owes you money:
after the order is completed
after the service is first delivered
after the service is completely delivered
after some period of time based on the terms of the sales order
For a hotel, usually you ask for money after the service has been completely delivered, but perhaps with a deposit, or intermediate payments for a long stay.
An invoice is not necessarily for one sales order. You can combine multiple sales orders into one invoice.
An invoice has line items referencing the sales order line items that you are requesting payment for.
You may have to issue multiple invoices for the same person/sales order.
EDIT 3 added design + cleanup
Every base table is the rows satisfying some statement. Find the statement.
Customer is the rows satisfying: customer [CustomerId] named [CustomerName] lives at ...
Product is the rows satisfying: product [ProductId] is named [Productname] costing [ProductPrice]
OrderDetail is the rows satisfying: orderDetail [OrderDetailId] of order [OrderId] is quantity [quantity] of product [ProductId]
Order is the rows satisfying: customer [CustomerId] ordered [OrderId] on [dateOfOrder]
What rows do you want in Bill? I'll guess...
Bill is the rows satisfying:
Bill [BillId] is for order [OrderId] on [dateOfBill] ... ???
You can find out some things about a bill by using its order. You must determine what else besides its date and order that you want know about a bill (eg to write one) and then what statement bill rows satisfy (ie finish the "...") that gives you that info directly (as with its date) or indirectly (as with its order).
I asked
what else besides its date and order that you want know about a bill (eg to write one)
BillId
dateOfBill
OrderId
order OrderId's customer's CustomerId, CustomerName, CustomerAddress ...
order OrderId's dateOfOrder
for every orderDetailId's orderDetail whose orderID = OrderId
quantity, ProductId, ProductNam,e ProductPrice, (quantity * ProductPrice) as productProduct
sum(quantity * ProductPrice) as total
over every orderDetail with OrderDetailId = OrderId
I asked
what statement bill rows satisfy that gives you that info directly or indirectly
You suggested
For the bills table I intend to have the following fields
Bill BillId (PK) CustomerId (FK) OrderId (FK) dateOfBill
Bill has to directly give us a BillId, dateOfBill and OrderId; they're nowhere else. But everything else can be got indirectly.
Bill is the rows satisfying:
bill [BillId] is for order [OrderId] and was billed on [dateOfBill]
The reason I mention statements is: one needs them to query and to determine FDs, keys, uniqueness, Fks, and other constraints. (Rather than using one vague intuitions.) This is explicit in design methods ORM2, NIAM and FCO-IM.
I determined the content of a bill above by finding what statement its rows will satisfy:
customer [CustomerId] named [CustomerName] at [CustomerAddress] ...
owes us $[total] for order [OrderId]
ordering [quantity] of product [ProductId] named [ProductName] # price $[ProductPrice] = [productProduct]
as recorded in bill [BillId]
This is a statement made from the statements given for each table, except that I need some statements not in any table yet, namely the stuff that (therefore) Bill needs to give. By replacing the statements by their tables we will get the query whose values are the rows we want.

MySQL Union (or similar) query

I have some booking data from a pair of views in MySQL. They match columns perfectly, and the main difference is a booking code that is placed in one of these rows.
The context is as follows: this is for calculating numbers for a sports camp. People are booked in, but can do extra activities.
View 1: All specialist bookings (say: a football class).
View 2: A general group.
Due to the old software, the booking process results in many people booking for the general group and then are upgraded to the old class. This is further complicated by some things elsewhere in the business.
To be clear - View 1 actually contains some (but are not exclusively all) people from within View 2. There's an intersection of the two groups. Obviously people can't be in two groups at once (there's only one of them!).
Finding all people who are in View 2 is of course easy... as is View 1. BUT, I need to produce a report which is basically:
"View 1" overwriting "View 2"... or put another way:
"View 1" [sort of] UNION "View 2"
However: I'm not sure the best way of doing this as there are added complications:
Each row is as approximately (with other stuff omitted) as follows:
User ID Timeslot Activity
1 A Football
1 A General
2 A General
3 A Football
As you can see, these rows all concern timeslot A:
- User 2 does general activities.
- User 3 does football.
- User 1 does football AND general.
AS these items are non unique, the above is a UNION (distinct), as there are no truly distinct rows.
The output I need is as follows:
User ID Timeslot Activity
1 A Football
2 A General
3 A Football
Here, Football has taken "precedence" over "general", and thus I get the picture of where people are at any time.
This UNION has a distinct clause on a number of fields, but ignores others.
So: does anyone know how to do what amounts to:
"add two tables together and overwrite one of them if it's the same timeslot"
Or something like a:
"selective distinct on UNION DISTINCT".
Cheers
Rick
Try this:
SELECT *
FROM
(SELECT *,
IF(Activity='General',1,0) AS order_column
FROM `Table1`
ORDER BY order_column) AS tmp
GROUP BY UserId
This will add an order_column to your original table that as value 1 if the Activity value is general; Doing this we can select this temporary table ordering by this column (ascending order) and all record with general activity comes after all others. After that we can simply select the result of this temporary table grouping by user id. The group by clouse without any aggregate function takes the first record that match.
EDIT:
If you don't to use group by without aggregate function this is an 'ugly' alternative:
SELECT UserId,
Timeslot,
SUBSTRING(MAX(CASE Activity WHEN "General" THEN "00General" WHEN "Football" THEN "01Football" ELSE Activity END) , 3)
FROM `Table1`
GROUP BY UserId,
Timeslot LIMIT 0 ,
30
Here we need to define each possible value for Activity.

Query Construction Combining UNION and LEAST

I have an email subscription table and a user table. I need to combine the two to get all the emails, since it's possible to create an account without subscribing and vice versa. Easy enough so far:
SELECT email FROM emailcapture
UNION
SELECT email FROM cpnc_User
Now, this gets me the complete list of all emails. For each email on this combined list, I need to add an extra piece of information: the created date. Both emailcapture and cpnc_User tables have a "created" field. The created date should be the earlier of the two dates, if both dates exist, or, if only one exists and the other is NULL, it should just be the one that exists.
How can I change this query so that it returns this extra piece of information, the created date? Keep in mind that the new query I seek should return exactly the same number of rows as the query above.
Thanks,
Jonah
SELECT i.email, MIN(i.date_creation) FROM
(SELECT email, date_creation FROM emailcapture
UNION ALL
SELECT email, date_creation FROM cpnc_User) as InnerTable i
GROUP BY i.email