I am developing an attendance system for school which will cater to both employees as well as students.
The current db schema is
attendance table
id - primary key for this table
daydate int(11) - stores timestamp of current day
timing_in varchar(18) - Start time for institution
timing_out - Closing time for institution
status - Status for the day, can be working day - 1 or holiday - 2
Then there are different tables for staff & students, which store the actual attendance values.
For staff, the attendance is stored in attendance_staff. The database schema is
attendance_id - foreign key, references attendance table
staff_id - id of staff member, references staff master table
time_in - stores in timing of a staff member
time_out - stores out timing of a staff member
status - attendance status - can be one among the list, like present, absent, casual leave, half day, late mark, on duty, maternity leave, medical leave etc
For staff, i am storing both present as well as not present entries in the table.
Now attendance for students has to be included with it.
Since status of each day is already stored in attendance table, can we store not present values for each student in the student attendance table.
Like, the student attendance table will store only entries for those days who are not present on a particular day.
The schema for attendance_student will be
attendance_id - references attendance table
student_id - references student table
status - will be leave / absent etc other than present.
Will it be efficient to calculate the present days from attendance table using outer join??
Thanks in advance.
You don't need an outer join to calculate attendance for students. You could simply count the records in your attendance table (one time, since it would be the same for all students) and then just select from your student attendance table to get absences.
If you'd prefer to count attendance with an outer join you could. It is likely to be more than efficient enough if you have an index on your attendance table primary key and on the foreign key from student attendance table to your attendance table.
Related
Each department is supposed to have only one statement per monthly billing cycle.
My goal is to figure out how many departments have been hit with more than one billing statement (having a value greater than $0.00) within the same billing cycle.
CONTEXT:
My current query is set to check only departments that are supposed to be billed monthly.
Department table has a one-to-many relationship with Statement table (a department is expected to have one or more statements)
Statement table has a one-to-many relationship with Trans table (a statement is expected to have one or more transactions)
Each billing statement has its own statement_close_date
c.type=‘periodic’ refers to a bill that only occurs once per billing cycle
d.period=1 represents accounts that are billed monthly
s.status=‘closed’ represents only closed statements
d.exp_date represents billing expiration date
v.status=‘active’ and d.status=‘active’ are meant to ensure that only active departments are being queried.
I also tried searching between specific expire dates on a per account basis.
The problem with my query is that it outputs the total number of billing statement_close_dates with a value greater than $0.00, instead of only checking for multiple occurrences within a billing cycle.
How can this query be modified to only output departments with more than one instance of a bill consisting of a periodic type charge greater than $0.00 within each department’s billing cycle?
QUERY:
SELECT s.department_id, s.statement_id, COUNT(s.statement_close_date) AS sd,
t.trans_id, from_unixtime(s.statement_close_date)
FROM statement s
INNER JOIN trans t
ON t.statement_id=s.statement_id
INNER JOIN cde c
ON t.cde=c.cde
INNER JOIN department d
ON s.department_id=d.department_id
WHERE from_unixtime(s.statement_close_date) BETWEEN
DATE_SUB(from_unixtime(d.exp_date), INTERVAL 1 MONTH) AND
from_unixtime(d.exp_date)
AND d.period=‘1’
AND s.status='closed'
AND t.dollars>0
AND c.type='periodic'
GROUP BY s.statement_id DESC
HAVING sd>1
SAMPLE OUTPUT:
department_id statement_id sd trans_id statement_close_date
1719712 9351464 3 98403043 2018-09-24
1719709 9351463 2 98403026 2018-09-24
1719708 9351462 2 98403010 2018-09-24
1719665 9351457 3 97374764 2018-09-24
I have 3 tables in access 2016 they are
EmployeeInformation(ID (PK), FirstName, LastName, Employee)
Trainings(TrainingID (PK), TrainingName)
CompletedTrainings(RecordID (PK), Employee, Training, Completed, Expired)
1st table Employee is a calculated field that is their first name and last name combined. 3rd table Employee and training are lookup fields from the other 2 tables and completed and expired are dates.
I want to create a query that will
-display all employees
-display all trainings
-display all completed and expired dates
-if there is an employee that did not complete a training that employee will be listed along with the training and the completed and expired date will be null.
Is this possible?
The situation. I am trying to make a report that lists the sales rep names (all of them; there are 50), the sales rep's state, and the total sales broken down by YYYY-MM for that state. If there are two or more sales reps in the state, they should each be listed with the same information for their state. How the final list is ordered does not matter, so long as all the information is included.
The problem. I also need totals by state in addition to the totals I have.
Here is my code:
SELECT
dim_sales_rep.sales_rep_name as 'Sales Rep',
dim_state.abbreviation as 'State',
date_format(dim_date.date, '%Y-%m') as 'Year-Month',
concat('$',sum(fact_sales.total_sales)) as 'Sales'
FROM
(
(
dim_sales_rep
JOIN dim_state ON dim_sales_rep.state_key = dim_state.state_key
)
JOIN fact_sales ON dim_sales_rep.sales_rep_key = fact_sales.sales_rep_key
)
JOIN dim_date ON fact_sales.date_key = dim_date.date_key
GROUP BY dim_date.year, dim_date.month, dim_state.abbreviation, dim_sales_rep.sales_rep_name
Sample Output:
Rep State Year-Month Sales
Michele Harris GA 2010-08 $679.79
T.S. Eliot GA 2010-07 $2938.74
It should look like this:
Rep State Year-Month Sales
Michele Harris GA 2010-08 $679.79
Georgiana Woe GA 2010-08 $482.98
State total $1162.77
Or like this:
Rep State Year-Month YM Total State Total
Michaele Harris GA 2010-08 $679.79 $1162.77
Georgiana Woe GA 2010-08 $482.98 $1162.77
Here is the data structure:
table fact_sales
date_key (PK) Surrogate Key
account_key (PK) Surrogate Key
sales_rep_key (PK) Surrogate Key
total_sales Total sales dollars.
count_of_products Number of products sold
table dim_state
state_key (PK) Surrogate Key
abbreviation e.g. AL or CA
name e.g. California
table dim_account
account_key (PK) Surrogate Key
account_name
account_address
state_key Surrogate Key
effective_date Starting date that this record is active
expiration_date Ending date that this record is active
is_current Represents the active record
table dim_sales_rep
sales_rep_key (PK) Surrogate Key
sales_rep_name
state_key Surrogate Key
effective_date Starting date that this record is active
expiration_date Ending date that this record is active
is_current Represents the active record
table dim_date
date_key (PK) Surrogate Key date e.g. 2011-01-01
month e.g. 01
year e.g. 2011
Notes:
PK: Denotes that the column is the primary key or is part of the primary key of the table.
Surrogate Keys are represented as numeric and do not represent actual values from an application. For example date_key could be 1,2,3,4, etc. and is not a real date.
Assume that dim_date contains all dates for all time.
Assume that if the column has the same name in a different table that they are equivalent.
When you group by just the state, you get one row per state in your result set. That's what GROUP BY means: aggregate your data broken out by the column values it mentions.
Use this:
GROUP BY dim_date.year, dim_date.month, dim_state.abbreviation, dim_sales_rep.sales_rep_name WITH ROLLUP
And, formatting your dates well can be done using MySQL's date functions.
Try this:
SELECT DATE_FORMAT(STR_TO_DATE(CONCAT_WS('-',2014,3,1),'%Y-%m-%e'),'%Y-%m')
My reservation system allows us to purchase credits for clients in terms of pre defined packages. I'm struggling with how I record and calculate available credits.
Let's say we're talking about a car wash service. A client can have multiple cars and can purchase the following services, 'Wash and Wax' and 'Detailing'.
Client 1 has two cars, Car A and Car B. He brings them both in and purchases:
Car A - 1 Wash and Wax
Car A - 1 Detailing
Car B - 10 Wash and Wax
Car B - 1 Detailing
This generates 4 rows in my Purchases table, one for each service purchased.
In my DB I have two related tables tracking purchases and reservations. Table 1 Purchases, Table 2 Reservations.
In Purchases I have the following fields of note:
id
client_id
car_id
service_id
credits_purchased
credits_scheduled
credits_used
cart_id
Then in my Reservation table I have the following fields of note:
id
client_id
car_id
service_id
reservation_date
completed_datetime
car_in_datetime
car_out_datetime
purchase_id
I track the credits available by updating the Purchases table fields credits_used and credits_on_schedule as events happen.
For example, when the client makes a reservation the system adds a new record in the Reservations table, once this happens the system also runs an update query and adds +1 to the related Purchases table credits_on_schedule. When the Reservation is updated to complete the system also updates the Purchases table and adds -1 to credits_on_schedule and +1 to credits used. Simple math between credits_purchased, credits_used, and credits_on_schedule derive what credits are available for a client to use.
I feel like this isn't a good way to track the credits. My question is what is a better implementation? Should I just track credits_purchased then use count queries on the Reservation table to calculate credits_used and credits_on_schedule? Should I be using a pivot table to track? I can't seem to wrap my head around what is the cleanest design.
It looks to me that the design is ok in general.
A reservation can only have one purchased related to it so purchase_id field is a foreign key in Reservation table.
Nevertheless, my advise to you is to create a log system of all these record updates.
As you mentioned, as events are fired the system updates the calculated fields.
What if for some reason the system fails at a certain point? You should be able to track these events.
One way to avoid this is, as you mentioned, calculate credit_used by a count query on all completed reservations.
I would like to build a very basic daily sales report. I'm am trying to decide how to structure the database to best accomplish this. Here is a use case for it:
On Jan 5, 2011, Provider A makes $500 total off of its products
On Jan 5 2011, Provider A makes $200 total off of its products
On Jan 6, 2011, Provider B makes $450 total off of its products
On Jan 6, Provider B makes $75 total off of its products
The current structure I have is:
PROVIDER table
pk
provider
PRODUCT table
provider (FK)
product
start_date (sales)
end_date
The start_date and end_date are when sales on the product may occur. It is only used for reference, and does not really affect anything else.
SALES table
product (FK)
sales
How to store date ??
sales would be the daily proceed ($) for sales from that product.
I'm not quite sure how to store the sales. Sales would only be calculated as a daily sum for each product. What would be the best way to structure the SALES table? Thank you.
Product Table:
This table should be 'transitory' in nature. Meaning that it is flexible to change over time.
In 2011 you may sell Product A for $15.99, but in 2012 you want to sell the same product for $16.99, so you want your table to be flexible enough to this type of change.
Although there is flexibility with the data stored within this table, care must be taken if you ever delete a product. If you delete a product, it will either orphan any matching sales transactions in the sales table, or delete them (depending upon FK behavior).
Sales Table:
This table should be 'transactional' in nature. Meaning that a row represents a product linked to a sale, frozen in time.
If buyer A purchased Product A for $15.99 in 2011, you want to record this transaction as is, nothing changes with the data at any point in time, it reflects a transaction.
If buyer B purchased the same Product A but for $19.99 in 2012, you want to record this as a separate transaction. Sure it is the same product, but this row represents a new transaction.
With the aforementioned setup, you can change prices as you see fit in the product table, but it won't affect already occurred sales recorded in the sales_transaction table.
Pseudo schema:
product:
id int(11) unsigned not null auto_increment
name varchar(255)
price decimal(14.2)
primary key (id)
unique key (name)
sales_transaction:
id int(11) unsigned not null auto_increment
product_id int(11) unsigned not null
provider_id int(11) unsigned not null
price decimal(14.2)
created_at datetime default '0000-00-00 00:00:00'
foreign key (product_id) references product('id') on delete cascade
foreign key (provider_id) references provider('id') on delete cascade
provider:
id int(11) unsigned not null
name varchar(255) not null
primary key (id)
unique key (name)
Now, you can run queries to get summations of any product for any date for any provider, as you requested in your question.
Sample Query:
# On Jan 5, 2011, Provider A makes $500 total off of its products
SELECT prov.*, SUM(sales.price)
FROM
provider AS prov
INNER JOIN
sales_transaction AS sales on sales.provider_id = prov.id
WHERE
provider.name = 'Provider A'
AND
sales.created_at BETWEEN '2012-01-05 00:00:00' AND '2012-01-05 23:59:59'
GROUP BY
prov.id
The schema provided is skeletal in nature, so feel free to add columns as your business requirements dictate, but it should get you going in the right direction.
Also, a final piece of advice, I would recommend storing your datetimes in UTC. If you opt to store in local timezone you will run into any number of headaches if you do any sales requiring conversion from your local timezone.
Why not a date field in the sales table? That would make each record the sales total for a certain product, on a certain date.