I am trying to build a SELECT statement on a MySQL view that will end up as a resource on a calendar app. Clients are booking out a piece of equipment for a period of time (bookings). Payment (payments) is taken at the beginning of the hire period for the equipment but further payments can be made if the hire period is extended. Therefore a single booking will have one, possibly many payments associated with it. Payments are recorded with the amount paid and the date they are paid.
Bookings for equipment must appear on the calendar if the date being viewed is within the hire period. Also, and this is the part I am having trouble with, payments, if they have been made on the date viewed, must be displayed (the reason for this is that my customer wants a daily total of takings for hires). If they haven't made a payment on the date viewed then the amount must appear as 0.
My view is built from three tables - bookings, payments and clients. The clients table is unimportant in this problem as it is just used in the view to generate the client name to be displayed on the calendar.
[![bookings][1]][1]
[![payments][2]][2]
The view is shown below
[![view_bookings_detail][3]][3]
This is what I am attempting to achieve. When the user opens the calendar or changes the calendar date, that date is used in my resource SELECT query as a parameter. In the first example we are viewing 04/07/2022. The parameter [selected_date] is set to '2022-07-04'. My initial SELECT statement was -
SELECT client_id, title, longterm_fee FROM view_bookings_detail WHERE start_date <= '[selected_date]' AND end_date >= '[selected_date]'
This returns -
[![calendar resource feed][4]][4]
Clearly this is no good as it would result in multiple entries for both hirer's. If I amend the select statement to -
SELECT client_id, title, longterm_fee FROM view_bookings_detail WHERE start_date <= '[selected_date]' AND end_date >= '[selected_date]' AND ltf_paid_on = '[selected_date]'
This returns -
[![amended calendar resource feed][5]][5]
This returns what I want but only because the two hirer's made payments on 04/07/2022.
If I were to view 05/07/2022, for instance, using the above logic, no records would be selected as no payments were made on 05/07/2022. What I would need returned in this case is a single record for each hirer with the longterm_fee showing as 0
I don't know how to achieve this. Anyone any ideas please?
Related
I'm trying to make a sum iif function which checks based on an employee's hire date and the ending pay period date whether they are part of the payroll period. So my idea was sum(iif([table1].[hiredate]<=[table2].[ppend],1,0))
While it works well for some, for some employees the number it gives is ridiculous. To give you an idea, there are 200 records for ppend, but it returns for some employees especially those who are well before the earliest ppend date, a number of 400 upward to 450. I'm also attempting to have it compare relative to the current date as well so I've used sum(iif(table1.hiredate<=table2.ppend<=date(),1,0)) but it largely leads to the same result. Could anybody help. Perhaps there is a factor I've neglected.
For table 1 the column data is in this order: employee ID, name, hire date and table 2 is payroll date, pp beg, pp end.
I am developing a php/mysql database.
I have a table called ‘actions’ which (amongst others) contains fields hrs, mins, actiondate, invoiceid and staffid.
For any particular actiondate there could be any number of actions carried out by various staff who would enter their time as hrs and mins.
What I need to do is produce a table which for each date and for a specific member of staff and invoice, adds up all of the hrs and mins for each date as a decimal, rounds it up to the nearest quarter and displays that result. I also need to be able to add up all of those results and display that total.
For example, if on March 1st, person with staffid=23 had carried out 4 actions for invoiced 121 lasting, 1h2m, 23m, 10m and 20m the total for that day would be 62+23+10+20 = 115m = 115/60 = 1.92 which would be rounded up to 2.00.
I can get each day’s total (maybe not very elegantly) and display it against the date using the code below
SELECT actions.`actiondate`,
(FORMAT((((CEIL((((60*SUM(hrs))+SUM(mins))/60)*4))/4)),2)) AS dayfeeqtr
FROM actions
WHERE staff.staffid=’23’
AND invoiceid=‘121’
GROUP BY actions.`actiondate`
However, what I can’t work out, is how can I add up all of these rounded up results for that invoice and that member of staff.
Can anyone help please?
If I understand correctly, you can use a subquery:
SELECT sum(dayfeeqtr)
FROM (SELECT a.`actiondate`,
FORMAT((((CEIL((((60*SUM(hrs))+SUM(mins))/60)*4))/4)), 2) AS dayfeeqtr
FROM actions a
WHERE s.staffid = '23' AND invoiceid = '121'
GROUP BY a.`actiondate`
) a;
I do note that your query is not correct -- for instance, there is a reference to staff, which is not in a from clause. However, you say that this is working, so I assume the errors are a transcription problem.
(Table names in quotes)
Let's say there are "users" that try to sells "products". They earn a commission on all "product_sales" (id, product_id, user_id, total, sale_date). I want to somehow store their commission rate based on certain dates. For example, a user will earn 1% from 2015-01-01 to 2015-01-15, 2% from 2015-01-16 to 2015-01-28, and 3% from 2015-01-29 onwards.
I want to run a query that calculates the total commissions for a user in January.
I want to run a query that calculates daily earnings in January.
How do I store the commission rates? One idea was having a table "user_commissions" that has (id, user_id, commission_rate, from_date, to_date). It would be easy to calculate the rate for (1) if commissions stayed the same, in which case I'd do this:
SELECT (sum(total) * 0.01) as total_commissions FROM product_sales WHERE user_id = 5 and sale_date between '2015-01-01' and '2015-01-31'
But with commission rates variable this is more complex. I need to somehow join the commissions table on each sale to get the right totals.
Another question would be:
How do I store the users' current commission rate that doesn't have an expiration date and include that in the reports? In my example, "3% from 2015-01-29 onwards". This has no end date.
Your table structure is a very reasonable structure and often used for slowly changing dimensions. Storing the effective and end dates in the structure is important for efficiency.
One way to store to_date for the most recent commission is to use NULL. This allows you to do:
select *
from commissions
where to_date is null
to get the most recent record.
However, a better way is to use some far distant date, such as '9999-12-12'. This allows you get the most recent commission using:
where curdate() between from_date and to_date
This is an expression that can also make use of an index on from_date, to_date.
Honestly, I would store user commission percentages and the effective dates of those commissions in one table.
TABLE: COMMISSION
user_id, date_effective, commission
In the other table I would store sales data. With each sale, I would keep the commission the salesperson got on the sale. (Added bonus, you can change the commission on any sale, like an override of sorts.)
TABLE: SALE
sale_id, sale_date, user_id, sale_amount, commission
When you create the row in your program, you can grab the correct commission rate using the following query:
SELECT commission from commission WHERE user_id=[user's id] AND date_effective<=[sale date, today] ORDER BY date_effective ASC;
MySQL Left Joins, and SQL in general, can get really tricky when trying to join on dates that don't exactly match up. (Looking back, basically.) I am struggling with the same problem right now without the luxury of the solution I just suggested.
(This whole post is based on the assumption that you aren't going to be directly interacting with this database through a DBMS but instead through an application.)
where I come from:
I have the tables 'event', user and user_event. Table event stores datetimes for start and end of an event. User_event holds information in which event a user is attending. Now it is easy possible to calculate the SUM of time a certain user is scheduled in events by just adding up all event durations.
But I need something different. Assuming that it is monday and user A is attending an event from 9-10am and from 2-3pm. The sum of these events is 2hrs. But I want to calulate how long the presence of a user is to take part in these events. In my example this is 6hr (from 9am - 3pm). I achieved this for one day (with time difference of max(event) and min(event) for the user and a given day.
Where I wanna go:
But I can´t find a solution for the task to sum the presence for the whole week. I need to add up all presence-sums for each day. But I cannot use the solution given for one day because min() and max() will only give me unique min and max values for the whole week and not for each day of the week.
Hope I described it well enough.
Thanks!
Make a GROUP BY on the days first, then on the week:
select
sum(d.dayFinish - d.dayStart) as weeklyPresence,
week(d.day) as weekNumber
d.userId
from (
select
to_date(e.startDate) as day,
min(e.startDate) as dayStart
max(e.finishDate) as dayFinish,
e.userId
from events e
group by to_date(e.startDate), e.userId
) d
group by week(d.day), d.userId
(I did not follow the actual syntax, some type conversions may be needed).
I suppose you have an Events table with startDate and endDate columns, and a userId foreign key that refers to the user.
The to_date() function rounds to the day (we group on that first), and the week() function determines the week (that's our second grouping).
I'm building upon a solution I developed a while ago - ticket booking. I now need to add a feature to allow tickets to be "held" during purchasing to make them appear as sold to another customer coming to the site (preventing double-booking).
Details on the original tables are in my previous question, MySQL - Trying to count tickets sold for an event. The tickets table now has a held_until DateTime value, and a paid tinyint (bool) value.
I need the events.capacity - COUNT(tickets.id) AS available to now only count those tickets which either:
Have a paid value of 1
Have a paid value of 0 and held_until > now()
I've tried adding WHERE and HAVING clauses, but these prevent events where no tickets have been sold from showing. I also had a play around with nested queries but didn't get anywhere with that either...
Any suggestions?
Modify Andomar's suggested query (in the other topic) as below :
change
ON events.id = tickets.event_id
to
ON ( events.id = tickets.event_id AND ( tickets.paid = 1 OR tickets.held_until > now() )
Even if all the required information can be found in your other topic, it would probably have been a good idea to repeat some relevant details here.