SQL language in MS ACCESS 2016 - sql

i need help with some query in MS ACCESS 2016 with SQL language.
I have a table with 20 employers, and the table includes name, last name, gender, date of birth, date of employment and payment.
I need to calculate specific age, I mean, I want to know who is for example 25 years old of my employers, i dont know how to write command in SQL language to calculate that, i would be very grateful if someone can help me.

You cannot calculate 100% correct age directly in SQL in a simple way.
So use an UDF (user defined function) like this:
Public Function AgeSimple( _
ByVal datDateOfBirth As Date) _
As Integer
' Returns the difference in full years from datDateOfBirth to current date.
'
' Calculates correctly for:
' leap years
' dates of 29. February
' date/time values with embedded time values
'
' DateAdd() is used for check for month end of February as it correctly
' returns Feb. 28. when adding a count of years to dates of Feb. 29.
' when the resulting year is a common year.
' After an idea of Markus G. Fischer.
'
' 2007-06-26. Cactus Data ApS, CPH.
Dim datToday As Date
Dim intAge As Integer
Dim intYears As Integer
datToday = Date
' Find difference in calendar years.
intYears = DateDiff("yyyy", datDateOfBirth, datToday)
If intYears > 0 Then
' Decrease by 1 if current date is earlier than birthday of current year
' using DateDiff to ignore a time portion of datDateOfBirth.
intAge = intYears - Abs(DateDiff("d", datToday, DateAdd("yyyy", intYears, datDateOfBirth)) > 0)
End If
AgeSimple = intAge
End Function
Copy and paste the code into an empty module.
Then run a query:
Select *, AgeSimple([DateOfBirth]) As Age
From YourTable
Where AgeSimple([DateOfBirth]) >= 25
Of course, replace table and field names with those of yours.

Related

Access SQL SELECT * WHERE Weeknum<CurrentWeek AND Year<=CurrentYear

I am sure i am missing something obvious, but i cant figure this out.
My problem is very simple
i have a table that contains the following information:
Year, Weeknumber, Data
What i want is to SELECT only data where the weeknumber is less that the current week. That is easy. But what i really want is all data that is registered before the current weeknumber AND current year.
Meaning if i have the following data:
Year Week Data
2019 20 123
2019 21 234
2020 20 345
2020 21 456
If the current week is 21 of 2020 then i want the output to be:
year Week Data
2019 20 123
2019 21 234
2020 20 234
I dont want 2020 - 21 because that is the current year/week
My current query is:
SELECT T.Year, T.Week, T.Data
FROM tblData AS T
WHERE Year<=year(Date()) AND Week<Weeknumber(Date())
The problem with this query is that it doesnt show weeks above 21 in 2019 which i want it to do. I know why this sql doesnt work, but cant figure out how to do it correctly.
How do i do this?
Year is a reserved word and should not use reserved words as names for anything. I used Yr as field name.
Consider:
SELECT Yr, Week, Data
FROM Table1
WHERE [Week] Between 1 And IIf([Yr]=Year(Date()), DatePart("ww", Date()) - 1, 53);
As you are from Denmark, the table will most likely reflect years and weeks according to ISO 8601. However, no native function of VBA will return the ISO 8601 year and week of a date, and - for dates around New Year - the year will often differ from the calendar year.
Thus, functions to return the ISO 8601 year and week are needed:
Public Const MaxWeekValue As Integer = 53
Public Const MinWeekValue As Integer = 1
Public Const MaxMonthValue As Integer = 12
Public Const MinMonthValue As Integer = 1
' Returns the ISO 8601 week of a date.
' The related ISO year is returned by ref.
'
' 2016-01-06. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function Week( _
ByVal Date1 As Date, _
Optional ByRef IsoYear As Integer) _
As Integer
Dim Month As Integer
Dim Interval As String
Dim Result As Integer
Interval = "ww"
Month = VBA.Month(Date1)
' Initially, set the ISO year to the calendar year.
IsoYear = VBA.Year(Date1)
Result = DatePart(Interval, Date1, vbMonday, vbFirstFourDays)
If Result = MaxWeekValue Then
If DatePart(Interval, DateAdd(Interval, 1, Date1), vbMonday, vbFirstFourDays) = MinWeekValue Then
' OK. The next week is the first week of the following year.
Else
' This is really the first week of the next ISO year.
' Correct for DatePart bug.
Result = MinWeekValue
End If
End If
' Adjust year where week number belongs to next or previous year.
If Month = MinMonthValue Then
If Result >= MaxWeekValue - 1 Then
' This is an early date of January belonging to the last week of the previous ISO year.
IsoYear = IsoYear - 1
End If
ElseIf Month = MaxMonthValue Then
If Result = MinWeekValue Then
' This is a late date of December belonging to the first week of the next ISO year.
IsoYear = IsoYear + 1
End If
End If
' IsoYear is returned by reference.
Week = Result
End Function
' Returns the ISO 8601 year of a date.
'
' 2016-01-06. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function YearOfWeek( _
ByVal Date1 As Date) _
As Integer
Dim IsoYear As Integer
' Get the ISO 8601 year of Date1.
Week Date1, IsoYear
YearOfWeek = IsoYear
End Function
An example:
? Week(#2024/12/31#)
1
? YearOfWeek(#2024/12/31#)
2025
Now, use these in your query:
SELECT
T.Year,
T.Week,
T.Data
FROM
tblData AS T
WHERE
T.Year * 100 + T.Week < YearOfWeek(Date()) * 100 + Week(Date())
And you can safely keep Year as the field name as long as you prefix it in queries with the table name as you already do or wrap it in brackets: [Year].
After further testing, June7 was very close, but that sql ended up removing the weeks greater than current week in 2019 (Which i didnt want). I might not have been clear enough in my question, but here is the sql WHERE criteria that gave me what i wanted. Which is, i only want the query to remove data from the current week in the current year. everything older than that, i want shown.
WHERE tbl.Week Between 1 And IIf(tbl.Yr=Year(Date()),Datepart("ww",Date())-1,53)
but thanks for your help #June7, since you guided me straight to the answer

Setting Access dates to various weekdays of the month

I have done a lot of research over the internet for something to help me with what I am trying to do, but haven't been able to come up with anything that helps my situation.
I'm new to using MS Access (using 2013 version) and I am working with a database through my SharePoint 2013 site. What I have is a SharePoint site that keeps track of lots of events through multiple lists. Essentially what I am trying to do is create a list template in SharePoint that I can just upload to the site instead of re-creating the list from scratch every month. With this list I have 1800 events per month and am trying to set the "Date" fields to the first, second, third, etc. Monday of the month, I am trying to do this for Tuesday through Friday also, so that way I don't have to manually set 1800 dates.
I figured this would be possible through MS Access rather than through SharePoint itself. At first I thought I would be able to set the default value to what I need each date field to be, but from my understanding this won't work, so I'm trying to figure out if there is a way to accomplish this in SQL. Now keep in mind that I have never used SQL before so I really don't know what I'm doing with it.
So in case that I didn't explain what I'm trying to do well, I'm trying to set date fields in Access to the 3rd Wednesday of the month, the second Thursday of the month, etc.
Any help is appreciated!
Thanks!
It will be some work to translate to pure SQL as the count of a weekday in a month will be either 4 or 5, but here is a generic function using VBA that does exactly this:
' Calculates the date of the occurrence of Weekday in the month of DateInMonth.
'
' If Occurrence is 0 or negative, the first occurrence of Weekday in the month is assumed.
' If Occurrence is 5 or larger, the last occurrence of Weekday in the month is assumed.
'
' If Weekday is invalid or not specified, the weekday of DateInMonth is used.
'
' 2016-06-09. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DateWeekdayInMonth( _
ByVal DateInMonth As Date, _
Optional ByVal Occurrence As Integer, _
Optional ByVal Weekday As VbDayOfWeek = -1) _
As Date
Const DaysInWeek As Integer = 7
Dim Offset As Integer
Dim Month As Integer
Dim Year As Integer
Dim ResultDate As Date
' Validate Weekday.
Select Case Weekday
Case _
vbMonday, _
vbTuesday, _
vbWednesday, _
vbThursday, _
vbFriday, _
vbSaturday, _
vbSunday
Case Else
' Zero, none or invalid value for VbDayOfWeek.
Weekday = VBA.Weekday(DateInMonth)
End Select
' Validate Occurence.
If Occurrence <= 0 Then
Occurrence = 1
ElseIf Occurrence > 5 Then
Occurrence = 5
End If
' Start date.
Month = VBA.Month(DateInMonth)
Year = VBA.Year(DateInMonth)
ResultDate = DateSerial(Year, Month, 1)
' Find offset of Weekday from first day of month.
Offset = DaysInWeek * (Occurrence - 1) + (Weekday - VBA.Weekday(ResultDate) + DaysInWeek) Mod DaysInWeek
' Calculate result date.
ResultDate = DateAdd("d", Offset, ResultDate)
If Occurrence = 5 Then
' The latest occurrency of Weekday is requested.
' Check if there really is a fifth occurrence of Weekday in this month.
If VBA.Month(ResultDate) <> Month Then
' There are only four occurrencies of Weekday in this month.
' Return the fourth as the latest.
ResultDate = DateAdd("d", -DaysInWeek, ResultDate)
End If
End If
DateWeekdayInMonth = ResultDate
End Function
Take a look at the WEEKDAY function.
For example you can get the next Sunday for any given date with the following:
=[date] - WEEKDAY([date]) + 7

Combining subqueries in Access SQL

I have two queries in Access 2007 which together provide the number of children over five in a set. I would like to combine these in SQL to make one query. Would somebody demonstrate the syntax on this example? Or is there a simpler way of getting to the same result?
The first query, called qryChildrenOverFive, is
SELECT
tblEventParticipants.EventParticipantsID,
DateDiff("yyyy", [tblChild.DoB],Date()) AS Age,
tblChild.DoB
FROM
tblEventParticipants
INNER JOIN (tblChild INNER JOIN tblChildParticipant
ON tblChild.ChildID = tblChildParticipant.ChildFK)
ON tblEventParticipants.EventParticipantsID =
tblChildParticipant.EventParticipantFK
WHERE (((tblEventParticipants.EventParticipantsID)=[CurrentID])
AND ((DateDiff("yyyy",[tblChild.DOB],Date()))>5));
The other, which uses the above as a subquery, is
SELECT qryChildrenOverFive.EventParticipantsID,
Count(qryChildrenOverFive.Age) AS NumOverFives
FROM qryChildrenOverFive
GROUP BY qryChildrenOverFive.EventParticipantsID;
As a sub-question, why won't Access SQL use the alias 'Age' in the first query in its WHERE clause?
DateDiff("yyyy", [tblChild.DoB],Date()) AS Age
will only return the difference in calendar years. To calculate the age, you need a function like this:
Public Function AgeSimple( _
ByVal datDateOfBirth As Date) _
As Integer
' Returns the difference in full years from datDateOfBirth to current date.
'
' Calculates correctly for:
' leap years
' dates of 29. February
' date/time values with embedded time values
'
' DateAdd() is used for check for month end of February as it correctly
' returns Feb. 28. when adding a count of years to dates of Feb. 29.
' when the resulting year is a common year.
' After an idea of Markus G. Fischer.
'
' 2007-06-26. Cactus Data ApS, CPH.
Dim datToday As Date
Dim intAge As Integer
Dim intYears As Integer
datToday = Date
' Find difference in calendar years.
intYears = DateDiff("yyyy", datDateOfBirth, datToday)
If intYears > 0 Then
' Decrease by 1 if current date is earlier than birthday of current year
' using DateDiff to ignore a time portion of datDateOfBirth.
intAge = intYears - Abs(DateDiff("d", datToday, DateAdd("yyyy", intYears, datDateOfBirth)) > 0)
End If
AgeSimple = intAge
End Function
and then:
AgeSimple([tblChild.DoB]) AS Age

Finding the next occurrence of a given date with MS Access query

I'm currently working on a database that stores software licensing information such as software name, purchase date, cost, quantity, etc... After the software has been owned for 12 months, we must pay a maintenance fee.
My question therefore, is how to design a query that will take the purchase date and compute the next occurrence of that date to be stored in the maintenance date field. Ex) If a license was purchased on 12/31/1999, I would need to pay maintenance on 12/31/2016.
I don't have a lot of experience with MS Access or SQL queries, and after researching this for a while, I am not even sure this is possible. I would appreciate any help you guys could give me!
Here's a function that will do exactly this:
Public Function DateNextAnnualDay( _
ByVal AnnualDay As Date) _
As Date
Dim SomeDate As Date
Dim NextAnnualDay As Date
Dim Years As Integer
SomeDate = Date
NextAnnualDay = AnnualDay
Years = DateDiff("yyyy", AnnualDay, SomeDate)
If Years < 0 Then
' Don't calculate hypothetical annual days.
Else
NextAnnualDay = DateAdd("yyyy", Years, AnnualDay)
If DateDiff("d", SomeDate, NextAnnualDay) <= 0 Then
' Next annual day falls earlier in the year than SomeDate.
NextAnnualDay = DateAdd("yyyy", Years + 1, AnnualDay)
End If
End If
DateNextAnnualDay = NextAnnualDay
End Function
Here is the syntax
SELECT DateAdd("yyyy",1,[MyDate]) AS MaintDate
FROM Table;
If you need to do more complicated querying you can write a function in a module and then access it in a query using VBA. For instance you can iterate through a loop to match a condition
Function GetNextDate(ByVal dteOriginalDate As Date) As Date
While dteOriginalDate <= DateTime.Now
dteOriginalDate = DateAdd("Yyyy", 1, dteOriginalDate)
Wend
GetNextDate = dteOriginalDate
End Function
Will iterate adding one year from the original date to the point at which the date is in the future. You can the build it into a query (using right-click -> build) so that each row runs through your code and applied the logic.
This will allow you to store the original licence date in your database and calculate the next due date without having to know (or amend) the intervening years.

Query for a specific length of time (Sql Access)

So I know how to query for a specific date range, but not for a specific length of time.
So rather than looking for records where someone was employed from x date to y date, I'm looking for records where they've been employed for 5 years. Kind of funky, but does anyone have any insight on this?
DateDiff just returns the difference in calendar years, so you need a custom function that uses DateAdd like this:
Public Function AgeSimple( _
ByVal datDateOfBirth As Date) _
As Integer
' Returns the difference in full years from datDateOfBirth to current date.
'
' Calculates correctly for:
' leap years
' dates of 29. February
' date/time values with embedded time values
'
' DateAdd() is used for check for month end of February as it correctly
' returns Feb. 28. when adding a count of years to dates of Feb. 29.
' when the resulting year is a common year.
' After an idea of Markus G. Fischer.
'
' 2007-06-26. Cactus Data ApS, CPH.
Dim datToday As Date
Dim intAge As Integer
Dim intYears As Integer
datToday = Date
' Find difference in calendar years.
intYears = DateDiff("yyyy", datDateOfBirth, datToday)
If intYears > 0 Then
' Decrease by 1 if current date is earlier than birthday of current year
' using DateDiff to ignore a time portion of datDateOfBirth.
intAge = intYears - Abs(DateDiff("d", datToday, DateAdd("yyyy", intYears, datDateOfBirth)) > 0)
End If
AgeSimple = intAge
End Function
Then use SQL similar to:
Select *
From PersonTable
Where AgeSimple([EmploymentDate]) = 5
For Mr. Monkey:
Please pay attention to the in-line comments which explain in full. For example:
' Decrease by 1 if current date is earlier than birthday of current year
To serve this purpose, three "awfully convoluted" lines of code are added:
If intYears > 0 Then
intAge = intYears - Abs(DateDiff("d", datToday, DateAdd("yyyy", intYears, datDateOfBirth)) > 0)
End If
To illustrate the necessity of these, please consider these two examples:
EmploymentDate = #2001/5/1#
Employed = DateDiff("yyyy", EmploymentDate, Date) ' -> 15 years
Employed = AgeSimple(EmploymentDate) ' -> 15 years
EmploymentDate = #2002/11/15#
Employed = DateDiff("yyyy", EmploymentDate, Date) ' -> 14 years
Employed = AgeSimple(EmploymentDate) ' -> 13 years
Use the DATEDIFFFunction
WHERE DATEDIFF ( yy, startdate , enddate ) = 5