How to Properly Create a SQL Query - ms-access

Good Afternoon,
I am working on a database for someone that tracks the vehicles they use in their business. Due to vehicles having new license plates issued to them as they expire the business wants to track the current plate for each vehicle as well as all plates that were previously issued to each vehicle.
I have created a table for vehicles, tbl_vehicles.
I have also created a table for license plates, tbl_license_plates.
Being that each vehicle has multiple license plate records. I need on a form, frm_vehicles, (where certain data for each vehicle is updated) to show only the most recent license plate number to appear. This needs to happen even if the plate has expired...i.e...is no longer valid.
The problem that I am encountering is that I do not have sufficient SQL skills to construct a query that returns for each vehicle only the most recent plate. I wrote the below query and it returns the vehicle_master_id and the expiration date of the most recently issued plate.
However, when I try to add the license_plate_number to the query, it returns every plate that has every been issued for each vehicle. This is a problem because I need the query to return only the most recently issued plate, whether or not it is valid (unexpired).
So, the guidance that I am seeking is how to construct this query so that it returns the license_plate_number for only the most recently issued plate, regardless of validity.
Can someone point me in the right direction, please?
As suggested, here is the text of the query
SELECT tbl_license_plates.vehicle_master_id AS Vehicle, Max(tbl_license_plates.date_expires) AS Expiration_Date, tbl_license_plates.license_plate_number
FROM tbl_license_plates
GROUP BY tbl_license_plates.vehicle_master_id, tbl_license_plates.license_plate_number;

Consider:
SELECT tbl_License_Plates.* FROM tbl_License_Plates WHERE license_plate_master_ID IN
(SELECT TOP 1 license_plate_master_ID FROM tbl_License_Plates AS Dupe WHERE
Dupe.vehicle_master_ID = tbl_License_Plates.vehicle_master_ID ORDER BY date_issued DESC);
More info on subqueries http://allenbrowne.com/subquery-01.html
Another approach is to take your GROUP BY query that has vehicle ID and issue date and INNER JOIN with tbl_License_Plates with compound link on both ID and date fields. This will be a non-updatable query.

Consider using Max function to return max valid date, can find a lot on Google about that function. Something like:
SELECT tbl_License_Plates.vehicle_master_id, Max(tbl_License_Plates.date_expires) AS
MaxOfdate_expires
FROM tbl_License_Plates
GROUP BY tbl_License_Plates.vehicle_master_id;

Related

joining two tables in my sql desn't return a result set

Hi I have run in to a problem when retrieving a particular data set using 3 tables in a MySql database.Tables are as follows
Student
SID | Name | Age | Telephone
Term
TID | Start | End
Payment
PID | TID | SID | Value
SID is primary key of Student table. TID is primary key of Term table. PID is primary key of Payment table. TID and SID in Payment table are foreign key references.
Student table contains data of students. Term table contain data of term start and end dates. Payment table contain data about student payment. Records in Payment table may either contain TID or not. When it is a registration payment there will be no TID. Otherwise it is a term fee and there will be TID. What I want is a list of students that hasn't paid this terms fees until today. Asuume this TID is in a variable. How can I obtain the list of students ? IT SEEMS SUPER EASY. BUT I COULDNT FIND AN ANSWER THIS WHOLE DAY 😣
You want a list of just those students who do not have a TID-populated record whose start and end dates are either side of today, in Payment
SELECT * FROM
student
LEFT OUTER JOIN
(select * from payment where TID is not null and NOW() BETWEEN start and end) this_term_payments
on student.id = this_term_payments.sid
WHERE
this_term_payments.ID is null
There are many ways to skin this cat. Here is one. We filter the payments table down to just a list of this term's payments (that's the inner query). And left join that to students. Left join means we get all students, matched with this_term_payments if the this_term_payments row exists, or NULL in every this_term_payments column if the term payment doesn't exist. The where clause then filters the whole results set down to "just those who don't have a term payment" by looking for those nulls that the left join creates
FWIW, your question attracted close votes because it didn't include example data/demonstrate the level of your effort we like to see on SQL questions. If you'd included sample data for all your tables and an example result set you wanted to see out, it means we can write an exact query that meets your requirements.
This is a bit of a double edged sword for me; we can deliver exactly what you ask for even if you later realise it's not what you want (asking in English is far more vague than giving an example result set) but at the same time we basically become some free outsourced homework contractor or similar, doing your work for you and removing learning opportunities along the way. Hopefully you'll take this query (it's likely it doesn't output everything you want, or outputs stuff you don't want) and craft what you want out of it now that the technique has been explained.. :)
For an SQL question that was relatively well received (by the time i'd finished editing it following up on the comments), and attracted some great answers take a look here:
Fill in gaps in data, using a value proportional to the gap distance to data from the surrounding rows?
That's more how you need to be asking SQL questions - say what you want, give example data, give scripts to help people create your same data so they can have a play with their idea without the boring bits of creating the data first. I picked on that one because I didn't even have any SQL attempts to show at the time; it was just a thought exercise. Having nothing working isn't necessarily a barrier to asking a good question
Try this:
select s.name, p.value from Student s, Term t, Payment p where t.TID = p.TID and s.SID=p.SID and p.TID is null;

PowerSchool: How to query past enrollment

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

SQL Query get all construction plans order by missing parts

OK lets consider we have the following db shema:
ConstructionPlans
c_id
Part
p_id
PlanPart
c_id p_id
The Table Construction Plans has all the plans, Part has all the parts and PlanPart has an entry for every plan and part combination. I am trying to think of a query considering that you would want to get all the construction plans (literally all) and have them in order of the number of parts that are missing. I have all the parts I have in an array for this query. I would also like to be able to check all the missing parts for a plan later on (but I guess one would simply take alle the c_ids in PlanPart and substract with the other Query and a Where Clause with the parts one already has).
Thank you for your input :)
Assuming that you have a column quantity in your Part table and a coulmn name in you ConstructionPlan table
select p.p_id from Part p, PlanPart pp, ConstructionPlan cp where p.quantity=0 and p.p_id=pp.p_id and cp.c_id = pp.c_id and cp.name = '<your plan name goes here>'

Need to delete random tuples from database in SQL

We're hiring some third party Test engineers and programmers to help us with some bugs on our website. They would be working on a beta installation of our web application. The thing is that we need to give them a copy of our database, we don't want to give the entire database, its a huge database of companies. So we would want to give them a watered down version of it that has less than a fraction of the actual data -- just enough for making a proper test.
We have data in the following Schema:
COMPANIES
ID|NAME|CATEGORY|COUNTRY_ID.....
We also have a set number of categories and countries.
The thing is that we don't want the deletion to be too random, basically out of the hundreds of thousands of entries we need to give them a version that has a few hundred entries but such that, you have at least 2-3 companies for each country and category.
I'm a bit perplexed as how to do a select query with the above restriction much less delete.
It's a MySQL database we would be using here. Can this be even done in SQL or do we need to make a script in php or so?
Following select statement will select companies with first 3 id in ascending order for each category, country_id combination:
select id, name, category, country_id
from companies c1
where id in (
select id
from companies c2
where c2.category=c1.category and c2.countr_id=c1.country_id
order by id
limit 3
);
Not sure my answer will fit your needs since I am doing some assumptions that may be wrong, but you could try the following approach:
select category, country_id, min(id) id1, max(id) id2
from companies
group by country_id, category
order by country_id, category
This query only gives you 2 company ids instead of 3 and they will be the first and last id that match category and country.
Please note also I wrote this out of my mind and have no MySQL engine to test it.
Hope that helps or at least gives you a hint on how to do it.

What is the best way to count rows in a mySQL complex table

I have a table with the following fields (for example);
id, reference, customerId.
Now, I often want to log an enquiry for a customer.. BUT, in some cases, I need to filter the enquiry based on the customers country... which is in the customer table..
id, Name, Country..for example
At the moment, my application shows 15 enquiries per page and I am SELECTing all enquiries, and for each one, checking the country field in customerTable based on the customerId to filter the country. I would also count the number of enquiries this way to find out the total number of enquiries and be able to display the page (Page 1 of 4).
As the database is growing, I am starting to notice a bit of lag, and I think my methodology is a bit flawed!
My first guess at how this should be done, is I can add the country to the enquiryTable. Problem solved, but does anyone else have a suggestion as to how this might be done? Because I don't like the idea of having to update each enquiry every time the country of a contact is changed.
Thanks in advance!
It looks to me like this data should be spread over 3 tables
customers
enquiries
countries
Then by using joins you can bring out the customer and country data and filter by either. Something like.....
SELECT
enquiries.enquiryid,
enquiries.enquiredetails,
customers.customerid,
customers.reference,
customers.countryid,
countries.name AS countryname
FROM
enquiries
INNER JOIN customers ON enquiries.customerid = customers.customerid
INNER JOIN countries ON customers.countryid = countries.countryid
WHERE countries.name='United Kingdom'
You should definitely be only touching the database once to do this.
Depending on how you are accessing your data you may be able to get a row count without issuing a second COUNT(*) query. You havent mentioned what programming language or data access strategy you have so difficult to be more helpful with the count. If you have no easy way of determining row count from within the data access layer of your code then you could use a stored procedure with an output parameter to give you the row count without making two round trips to the database. It all depends on your architecture, data access strategy and how close you are to your database.