Excluding identical returns from ACCESS query when names are equal - sql

In MS ACCESS, I have a table containing names and dates for when a persons yearly exam expires. This exam is valid for 12 months, so the next exam is typically done before all 12 months have expired.
Table, called "Exam", looks like this (in the real table names are unique):
ID Name Dateexp
1 Peter 30/07/2020
2 john 10/09/2020
3 Bob 11/10/2019
4 Peter 25/06/2021
I have a query that shows the persons with a "valid" exam. I looks like this:
SELECT Name As Name, Dateexp As Expiry FROM Overall WHERE Dateexp > now();
It returns:
Name Expiry
Peter 30/07/2020
John 10/09/2020
Peter 25/06/2021
Problem is that "Peter" has done a new exam thereby extending his expiry date from 30/07/2020 to 25/06/21 and I only want the latest one to be shown.
Query should return:
Name Expiry
Peter 25/06/2021
John 10/09/2020
I am truly lost - does anyone have an idea as to how this can be solved?
Thank you!

You can use max and having clause:
Select name, max(dateexp) as dateexp
from overall
Group by name
Having max(dateexp) > now()

If I followed you correctly, you can just use aggregation, and filter with a having clause:
select name, max(dateexp) as expiry
from overall
group by name
having max(dateexp) > now();
This filters on names whose latest expiry date is in the future.

Related

Access SQL: Calculating Percent Change between two rows

I am trying to calculate the percentage change between two dates in Access.
The user inputs the start date, an end date and the desired percentage change. If the result matches the criteria it should return the name.
Please note this is the dd/mm/yy format.
This is the table I have:
Name | Payment | DateTime
John | 53.00 | 06/01/18
Mike | 23.16 | 12/07/18
Steve | 31.28 | 21/03/18
John | 58.30 | 22/04/18
For example, if the user inputs a start date of 01/01/18, an end date of 23/04/18, and a desired percentage change of 10 percent then it should return the name John.
Currently, this is the query I have:
SELECT Name
FROM UserPayments
WHERE DateTime >= '01/01/18' AND DateTime <= '23/04/18';
I would like to calculate the total percentage change for two entries. This should be the record date immediately after the first date and the date immediately before the second date.
I'm completely stuck on how to do this in Access (SQL).
I think I need to use a join, but I have not done these before.
There should be a Users table with a primary key of something like UserID, and that UserID should be used in the UserPayments table instead of the Name of the user.
Although it would by nice to use functions like First and Last, MS Access will not allow to use ORDER BY for sorting the details in a group defined by GROUP BY. Therefore, you will have to use subqueries to retrieve the two values for the percentage calculation. If you have a Users table like mentionned above and the DateTime value can be assumed to be unique per User, this could look like this:
SELECT Users.Name,
(SELECT TOP 1 Payment FROM UserPayments
WHERE UserID = Users.UserID AND DateTime Between #01/01/2018# And #04/23/2018#
ORDER BY DateTime DESC)
/
(SELECT TOP 1 Payment FROM UserPayments
WHERE UserID = Users.UserID AND DateTime Between #01/01/2018# And #04/23/2018#
ORDER BY DateTime ASC)
-1 AS PercentChange
FROM Users;
Be aware of rounding errors and format the result as a percentage.

Specific SQL Ordering

Bit of a newbie to SQL but I'm making my way in pretty well. My question, however, is of ordering things in a specific way. Say, for example, that I have the following table:
DATE RANGE NAME ORDER COUNT
5/5/14 - 5/6/14 Bob Food 3
5/5/14 - 5/6/14 Jim Drink 2
5/4/14 - 5/5/14 Bob Food 3
I would like to order these in a specific way:
DATE RANGE NAME ORDER COUNT
5/4/14 - 5/5/14 Bob Food 3
5/5/14 - 5/6/14 Bob Food 2
5/5/14 - 5/6/14 Jim Drink 2
To where it is ordered by where name and order are the same, count doesn't necessarily have to be the same, and that is all ordered by date range. I've tried various permutations of ORDER BY with no luck, but it seems to me like this should overall be a very simple query. Does anyone have any advice?
Here is a sqlFiddle for the code. You should GROUP BY NAME, ORDER, DATE RANGE, COUNT, then ORDER BY DATE RANGE.

Using SQLite to display repeated and new entries

I have a table with 5 columns, but I really need only information from two. Here is an example of that table, though mine has 1600+ records:
Date Name
2/18 Bob
2/18 Karen
2/19 Fred
2/20 Jared
2/21 Fred
2/22 Bob
2/23 Steve
2/24 Bob
2/25 Jared
I would like to set a date range and find which names were repeats and which were new. For example, if I did this for 2/18-2/21 and 2/22-2/25, I would see that in 2/22-2/25 Bob and Jared were also found in the 2/18-2/21 date range and that Steve was "new." Does anyone have any ideas on a SQLite query to accomplish this task?
You can do this using conditional aggregation, assuming your dates are really in a reasonable format.
select name,
(case when min(date> < STARTDATE then 'RETURNING'
else 'NEW'
end)
from table t
where date between STARTDATE and ENDDATE
group by name;

age from dob in sql

In the sql query, I am getting problem in the where clause.
I have a dob and ssn of people in a table. I need to find the youngest snr. customer. The age of youngest senior customer starts from 55. The data of DOB contains all the dob's of children,parent, senior customers. In the line "where" I have to write a condition that checks if the age is > 55 and has to be smaller amongst the senior customers.Please suggest me some ways .I posted a similar question before, but did nt get any reply that can help me in solving it.
I dont have the age parameter in my table.
SSn DOB
22 1950-2-2
21 1987-3-3
54 1954-4-7
I need to find the ssn corresponding to the age whcih has to be greater than 55 and smaller among above values .
In the script below, the sub-select finds the DOB of the youngest person 55 years of age or over; this is then used to find the corresponding SSN record(s). [This uses SQL Server syntax.]
SELECT yt.*
FROM *yourtable* yt
INNER JOIN
(
SELECT MAX(DOB) AS DOB
FROM *yourtable*
WHERE DATEADD(year, 55, DOB) < getdate()
) maxdob
ON maxdob.DOB = yt.DOB
n.b. you may find more than a single record if there is more than 1 person with the same DOB.
If you want to force this single restriction, add a TOP 1 clause in your SELECT statement.
hth
If you have the DOB then you can easily calculate the age based on the current date:
WHERE DATE_ADD(DOB, INTERVAL 55 YEAR) < NOW()
This will add 55 years to the DOB and if it is greater than the current time, it's true. This would indicate they are at least 55 years of age.

Advice on database design / SQL for retrieving data with chronological order

I am creating a database that will help keep track of which employees have been on a certain training course. I would like to get some guidance on the best way to design the database.
Specifically, each employee must attend the training course each year and my database needs to keep a history of all the dates on which they have attend the course in the past.
The end user will use the software as a planning tool to help them book future course dates for employees. When they select a given employee they will see:
(a) Last attendance date
(b) Projected future attendance date(i.e. last attendance date + 1 calendar year)
In terms of my database, any given employee may have multiple past course attendance dates:
EmpName AttandanceDate
Joe Bloggs 1st Jan 2007
Joe Bloggs 4th Jan 2008
Joe Bloggs 3rd Jan 2009
Joe Bloggs 8th Jan 2010
My question is what is the best way to set up the database to make it easy to retrieve the most recent course attendance date? In the example above, the most recent would be 8th Jan 2010.
Is there a good way to use SQL to sort by date and pick the MAX date?
My other idea was to add a column called ‘MostRecent’ and just set this to TRUE.
EmpName AttandanceDate MostRecent
Joe Bloggs 1st Jan 2007 False
Joe Bloggs 4th Jan 2008 False
Joe Bloggs 3rd Jan 2009 False
Joe Bloggs 8th Jan 2010 True
I wondered if this would simplify the SQL i.e.
SELECT Joe Bloggs WHERE MostRecent = ‘TRUE’
Also, when the user updates a given employee’s attendance record (i.e. with latest attendance date) I could use SQL to:
Search for the employee and set the
MostRecent value to FALSE
Add a new record with MostRecent set to TRUE?
Would anybody recommended either method over the other? Or do you have a completely different way of solving this problem?
To get the last attendance date use the group function called MAX, i.e.
SELECT MAX(AttandanceDate)
FROM course_data
WHERE employee_name = 'Joe Bloggs'
To get the max attendance date for all the employees:
SELECT employee_name, MAX(AttandanceDate)
FROM course_data
GROUP BY employee_name
ORDER BY employee_name
Query above will NOT return data for employees who haven't attended any courses. So you need to execute a different query.
SELECT A.employee_name, B.AttandanceDate
FROM employee AS A
LEFT JOIN (
SELECT employee_id, MAX(AttandanceDate) AS AttandanceDate
FROM course_data
GROUP BY employee_id
) AS B ON A.id = B.employee_id
ORDER BY A.employee_name
For employees who haven't attended any course, the query will return a NULL AttendanceDate.
The flag is redundant. The other way how to get last attend day by employee:
select top 1 AttandanceDate
from course_data
WHERE employee_name = 'Joe Bloggs'
order by AttandanceDate desc
This may already be the case, but the output from the AttandanceDate columns makes me suspicious that that column may not be a datetime column. Most RDBMS's have some sort of date, time, and/or date time data types to use for storing this information. In which KandadaBoggu's AND OMG Ponies responses are perfect. But if you are storing your dates as strings you WILL have issues trying to do any of their suggestions.
Using a date time data type usually also opens you to the possibilites of obtaining date details like:
e.g. SELECT YEAR(2008-01-01) will return 2008 as an integer.
If you are running SQL Server 2005 or 2008 or later, you can use row_number() do something like the following. This will list everyone, with their most recent attendance.
with temp1 as
(select *
, (row_number() over (partition by EmpName order by AttandanceDate descending))
as [CourseAttendanceOrder]
from AttendanceHistory)
select *
from temp
where CourseAttendanceOrder = 1
order by EmpName
This could be put into a view so you can use it as needed.
However, if you always will be focused on one individual at a time, it may be more efficient to make a stored procedure that can use statements like select max(AttandanceDate) for just the person you are working on.