In a simplified rental system, there are three relations:
Book: id, title, description
Copy: id, book_id
Booking: id, copy_id, rent_from, rent_until
For each book there exist many copies. If a customer rents a book, an available copy is selected and a corresponding booking record is created.
Now my problem: A customer selects a book, he/she wants to rent. The system needs to check, which copies are available for the given rental period.
What is the most elegant and fastest way to query the available copies?
Basically, step-by-step one would do the following:
Select all copies of the corresponding book
Select all bookings in the specified period of those copies
Check which copies of the book are not included in the selected bookings. If all copies are included, the book is not available for rent in the given period
Step 3 gives my a headache. How to do this in SQL? Can I probably even perform all three steps in one elegant query?
Assuming you have the bookid. You are looking for:
select c.*
from copies c
where not exists (select 1
from booking b
where b.copy_id = c.id and
b.rent_until >= #PeriodStart and b.rent_from <= #PeriodEnd
);
This is checking for overlapping time periods. There is an overlap if the booking ends after the period starts and if the booking starts before the period ends. The comparisons might be < and >, depending on whether a book can be rented on the rent_until date, or if it has to wait until the next day.
Related
I have a access table that has quarterly pricing data starting from 20100131 and goes on as 20100430, 20100731.... 20170131, 20170430. For each pricing date, there are many loans. Some loans stay in the portfolio, some loans are removed and some added for each pricing period. I would like to find the list of loans that exist in all periods and see their price for each period. So i have the "Loan_Number" field and "Price_Date" field. I would like to find the Loan Numbers that exist in all price date points. I appreciate the help.
Thanks!
Would have been nice to see some effort from you but I was intrigued with the challenge so here is what I accomplished.
1 - Need a dataset of all possible combinations of loan numbers and date values. So if you have a LoanNumbers table and a Periods table, create a Cartesian query called AllPairs:
SELECT LoanNumbers.Loan_Number, Periods.Price_Date FROM LoanNumbers, Periods;
If you don't have those tables, generate datasets with queries, assuming the data table has at least one record for every loan number and at least one record for every period:
SELECT DISTINCT Table1.Price_Date FROM Table1;
SELECT DISTINCT Table1.Loan_Number FROM Table1;
2 - Join AllPairs to data table for a 'find unmatched' query called LoanNoPeriod:
SELECT AllPairs.Loan_Number, AllPairs.Price_Date, Table1.Loan_Number, Table1.Price_Date
FROM AllPairs LEFT JOIN Table1 ON (AllPairs.Price_Date = Table1.Price_Date) AND (AllPairs.Loan_Number = Table1.Loan_Number)
WHERE (((Table1.Price_Date) Is Null));
3 - Final query:
SELECT * FROM Table1 WHERE Loan_Number NOT IN (SELECT AllPairs.Loan_Number FROM LoanNoPeriod);
Be aware these type of queries can perform very slowly and with very large datasets might not be practical.
I know this is somewhat of a specialized question since only a small percentage of members will even have heard of PowerSchool, but it's hard to find help for this. Given a start date and end date, I need to run a query that will return the student ID's for all students who were enrolled in the District during that time period. If I could use that with 'WITH AS', I could add it to an attendance query 'Where' clause like below. This is what I've got so far, but I don't know how to check it's accuracy:
SELECT * FROM Students
WHERE ID IN (
SELECT studentid FROM ps_adaadm_defaults_all
WHERE schoolid IN ('16', '28', '40')
AND calendardate >= '1-May-15'
AND calendardate <= '31-May-15'
GROUP BY studentid)
ORDER BY LastFirst;
"ps_adaadm_defaults_all" is a PowerSchool View that is mainly for ADM so my assumption here is that if a student ID exists in ps_adaadm_defaults_all with a date between the two given dates, that student was enrolled at least that day regardless of attendance, correct? Any PowerSchool users out there that can lend a hand?
I get results with this query but when I try to verify the accuracy by using the PowerSchool site, the results aren't exactly the same. What I mean by using the site is I log in as district admin, set Term to 15-16 year, School to desired school and select students whose last names begin with 'A'. I then start comparing the list it provides with the students from the query results whose last names begin with 'A'. I am noticing though that there are names that I get with my query that are not showing on the site and I think it's due to their exitdate being prior to the current schoolyear. Those students were obviously enrolled at that time, but their names aren't in the PowerSchool results. I'm thinking because they're not enrolled anymore? Is there any way for me to test the accuracy of this query? Am I even on the right track? Thanks in advance.
It sounds to me like you have two questions:
What is the best query to return all students who were enrolled during a given time period?
What is the best way to check that my query is selecting all records it should be?
I'd use the ps_enrollment view for your query. It includes student id, school id, and start and end dates, so it can be used to find all students who were enrolled at a certain point in time.
Students enrolled for the whole specified time period
SELECT UNIQUE pe.StudentID
FROM ps_enrollment pe
WHERE pe.schoolid IN ('16', '28', '40')
AND pe.EntryDate <= '05/01/2015'
AND pe.ExitDate >= '05/30/2015'
Students enrolled at any time within the specified time period
SELECT UNIQUE pe.StudentID
FROM ps_enrollment pe
WHERE pe.schoolid IN ('16', '28', '40')
AND (
(pe.EntryDate <= '05/01/2015' AND pe.ExitDate >= '05/01/2015')
OR (pe.EntryDate <= '05/30/2015' AND pe.ExitDate >= '05/30/2015')
OR (pe.EntryDate >= '05/01/2015' AND pe.ExitDate <= '05/30/2015')
)
In the above example, the three conditions inside the AND check for enrollments that either started before or on and ended after or on the first date, then the second date, and finally checks for any enrollments that happened in between the two dates.
Note: I used UNIQUE instead of GROUP BY. I think it fits what you're doing a little bit more.
The easiest way to check these numbers in the admin side is to use System Reports -> Membership and Enrollment -> Enrollment Summary by Date. This is an easy way to check enrolled students numbers at any point in time, and also will give you the list of those specific students. It includes inactive students.
You can double-check that it's working perfectly by entering a single date in your query instead of using a date range, and by checking that date against the Enrollment Summary by Date. When I did this for our district, my query pulled 7 extra records (out of over 7000), but upon investigation, all of those were due to bad reenrollment records, so it appears to be working correctly.
When you search PowerSchool from the admin website, it only returns active students regardless of what term you select. In other words, I can't select "2000-2001" from the terms list and magically have everything reflect that term.
I can think of a couple things that may be affecting your searches:
search by using a forward slash to include inactive students "/lastname"
if you are searching HS students - remember that seniors transfer to a special school when they graduate
A better way to verify your query results would be to use the ADA/ADM section under System Reports. Reduce your query to one date and then run the ADA/ADM by Date report for the same day.
Just came across this and for anyone that is reading through this, PowerSchool has come up with "as of" selections.
Examples:
*as_of=09/30/2020;enroll_status=0
*as_of=09/30/2020;track=D
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.
I am working on a personal project and needed some guidance with a mySQL database. I am trying to simulate an airlines reservation system where a user has a personal account added to an Accounts db table (with username and password information). Then I have my Flights db table to store all of the available flights. The Flights db table has all of the flights with information (columns) on departure city, arrival city, departure time, arrival time, price, available seats, and seat capacity.
My question is:
When a user books a flight I must update the available seat value (int) in the Flights table. But then I also must add the flight to the user's account in the Accounts table. I am wondering how to handle this in mySQL, do I have to add a new column to the Accounts table with the corresponding flight's table index from the Flight's db table. Then continue adding a booked flight column as a user books flights to keep track of all the flights a user has booked? Is there a better way to update the Accounts table with flights booked information?
All help is very much appreciated.
Honestly, I would probably go about this a little differently. You may think about adding an additional table that tracks seat reservations. Something like:
TABLE: Accounts
ID | First Name | Last Name | Username | Password
TABLE: Flights
ID | DepartureCity | ArrivalCity | DepartureTime | Price | SeatingCapcity
TABLE: Reservations
ID | Account_ID | Flight_ID | SeatNumber
You can then use SQL functions and math to determine the number of seats available on a particular flight and maintain just the Reservations table when making updates. This also links all flights a particular account is associated with and is not "hard coded" to a particular column. (ie: A user can reserve more than one flight)
The best way to achieve this is to introduce a new table Bookings. A possible structure might be
CREATE TABLE Bookings (user_id INTEGER NOT NULL, flight_id INTEGER NOT NULL);
Then you can fetch all flights of a given user by
SELECT f.* FROM Users u
LEFT JOIN Bookings b ON u.id = b.user_id
LEFT JOIN Flights f ON b.flight_id = f.id
WHERE u.id = ?
And count the bookings for a given flight by
SELECT count(*) FROM Flights f
LEFT JOIN Bookings b
WHERE f.id = ?
This structure has several advantages:
You don't have to change the schema if users book more and more flights. Changing the schema of your database is a quite complex an expensive operation. (BTW: There is a maximum column count in MySQL)
You have an point where you can add further fields that are concerned with bookings. Maybe you want to track reservations.
Its more natural to fetch and add data. If you add columns booked_flight_1 booked_flight_2 and so on. You have to check which slot isn't already taken, which gets more and more complex when you consider deletions. Here it as easy as running this
INSERT INTO Bookings (user_id, flight_id) VALUES (1, 2)
If have to check if a given flight is available, it might be better to check this using your program and insert the booking into the database, if it is.
Joins and transactions might be the techniques you will find useful. The MySQL documentation and every good book on relational databases will give you an introduction in this. Your question sounds to me, as a classical instructional example.
I have in my database a table called rooms that contain the rooms information and property ,and another table called reservation table that contain the Room Reserved, FromDate and ToDate .
What i want to do is to make the user pick room size that he want to reserve and pick the date for reserving the room ,then i provide for him the available rooms depend on the Room Reservation table.
here what i did:
SELECT * FROM Rooms,Reservations WHERE
Rooms.R_Size = 'roomSize' AND ('4/19/2013' NOT
BETWEEN Reservation.FromDate AND Reservation.ToDate AND '4/19/2013'
NOT BETWEEN Reservation.FromDate AND Reservation.ToDate)
The problem its return to me duplicate's rooms and even if its between the reserved date in specific reservation but its not between reserved date in another reservation still it will return it to me.
What i want is to check if the room is reserved at the same or between a specif date and if it is i don't want it to be selected and returned at all.
Thanks.. and sorry for my poor english
There are two problems with your query. One is that there is no condition on the join between rooms and reservations, such that rooms of the correct size will be returned once for each reservation satisfying the date tests. Another problem is that your date test is wrong as it will not detect existing reservations that is completely within the date interval of the new reservation.
A query like this one should give you the result you want:
SELECT * FROM Rooms
LEFT JOIN Reservations
ON Reservations.R_Number = Rooms.Number
AND Reservations.ToDate > '4/19/2013'
AND Reservations.FromDate < '4/20/2013'
WHERE Rooms.R_Size = 'roomSize'
AND Reservations.R_Number IS NULL
It works by joining the rooms to the reservations for that room, and then selecting the rooms for which there are no reservations that conflicts with the new reservation being made.(Old reservation that ends before the new one starts, or that starts after the new one ends are no problem).
What you are doing here is a cross join. Every row from table a (Rooms) is joined with every row in table b (Reservations).
In order to make your query work, you need to specify that Rooms.Rooms_Key = Reservations.Rooms_ForignKey in your where clause (or an explicit join [inner,left,right] and specify the ON fields as they are easier to read in my opinion - explicit-vs-implicit for more info).
Once you have converted the join type, the where clause will start to give you better results, and you should be able to modify it if you still need to at that point.