PostgreSQL, getting min and max date from text column - postgresql

I have such situation in table:
1 01.02.2011
2 05.01.2011
3 06.03.2012
4 07.08.2011
5 04.03.2013
6 06.08.2011
7
8 02.02.2013
9 04.06.2010
10 10.10.2012
11 04.04.2012
where first column is id (INT) and second column is TEXT in which may be written date in format 'dd.mm.yyyy'.
I would like to get:
1) lowest entered date in whole table and highest entered date in whole table.
2) lowest entered date in year 2012 and highest entered date in year 2012.
Lowest and highest date in year may be a same (like for year 2010) or field may be empty (like in row 7).
I am tying to use TO_TIMESTAMP but unsuccessfully.
Example:
SELECT (TO_TIMESTAMP(mydatetxt, 'DD.MM.YYYY'))
FROM " & myTable & "
ORDER BY (TO_TIMESTAMP(mydatetxt, 'DD.MM.YYYY')) ASC LIMIT 1
Also with BETWEEN I don't get wanted result.
How to write those two queries?
SOLUTION:
Thanks for all suggestions.
Igor's solution is most suitable and simple enough for me.
Dim sqlText As String = "SELECT min(to_date(nullif(mydate,''), 'DD.MM.YYYY')) FROM " & mytable
cmd1 = New NpgsqlCommand(sqlText, conn)
min = CDate(cmd1.ExecuteScalar())
If Not IsDate(min) Then
min = CType(CDate("01.01." & myyear) & " 00:00:00", Date)
End If
fromdate = CType(CDate(min), Date)
sqlText = "SELECT max(to_date(mydate, 'DD.MM.YYYY')) FROM " & mytable
cmd1 = New NpgsqlCommand(sqlText, conn)
max = CDate(cmd1.ExecuteScalar())
If Not IsDate(max) Then
max = CType(CDate("31.12." & myyear) & " 23:59:59.9999", Date)
End If
todate = CType(CDate(max), Date)

Try something like:
SELECT max(to_date(nullif(mydatetxt,''), 'DD.MM.YYYY')),
min(to_date(nullif(mydatetxt,''), 'DD.MM.YYYY'))
FROM table_name;
SELECT max(to_date(nullif(mydatetxt,''), 'DD.MM.YYYY')),
min(to_date(nullif(mydatetxt,''), 'DD.MM.YYYY'))
FROM table_name
WHERE date_part('year',to_date(nullif(mydatetxt,''), 'DD.MM.YYYY')) = 2012;

Related

Find all instances of a date in a date range - SQL Server

I need to find the price for an item for each financial year end date in a date range. In this case the financial year is e.g. 31 March
The table I have for example:
ItemID
Value
DateFrom
DateTo
1
10
'2019/01/01'
'2021/02/28'
1
11
'2021/03/01'
'2021/05/01'
SQL Fiddle
The SQL would thus result in the above table to be:
ItemID
Value
DateFrom
DateTo
1
10
'2019/01/01'
'2019/03/30'
1
10
'2020/03/31'
'2021/02/28'
1
11
'2020/03/01'
'2021/03/30'
1
11
'2020/03/31'
'2021/05/01'
You can solve it, but a prerequisite is the creation of a table called financial_years and filling it with data. This would be the structure of the table:
financial_years(id, DateFrom, DateTo)
Now that you have this table, you can do something like this:
select ItemID, Value, financial_years.DateFrom, financial_years.DateTo
from items
join financial_years
on (items.DateFrom between financial_years.DateFrom and financial_years.DateTo) or
(items.DateTo between financial_years.DateFrom and financial_years.DateTo)
order by financial_years.DateFrom;
The accepted answer is not correct, as it does not split out different parts of the year which have different values.
You also do not need a Year table, although it can be beneficial. You can generate it on the fly using a VALUES table.
Note also a better way to check the intervals overlap, using AND not OR
WITH Years AS (
SELECT
YearStart = DATEFROMPARTS(v.yr, 3, 31),
YearEnd = DATEFROMPARTS(v.yr + 1, 3, 31)
FROM (VALUES
(2015),(2016),(2017),(2018),(2019),(2020),(2021),(2022),(2023),(2024),(2025),(2026),(2027),(2028),(2029),(2030),(2031),(2032),(2033),(2034),(2035),(2036),(2037),(2038),(2039)
) v(yr)
)
SELECT
i.ItemID,
i.Value,
DateFrom = CASE WHEN i.DateFrom > y.YearStart THEN i.DateFrom ELSE y.YearStart END,
DateTo = CASE WHEN i.DateTo > y.YearEnd THEN y.YearEnd ELSE i.DateTo END
FROM items i
JOIN Years y ON i.DateFrom <= y.YearEnd
AND i.DateTo >= y.YearStart;

MS Access : Dealing with today's date in calculated field expression

Hi I am creating a table in MS Access to store the details of children in a school.
I have a field called YearGroup which needs to calculate the school year they are in based on their date of birth and whether they have been moved up or down a year.
I.e. if the expression deems they are six years old they should be placed in year 2. If they were moved down or up a year they should be in year 1 or 3 (this is based on another field in the table called YearModifier).
The code I have at the moment is this:
Year(Now()) - IIf(Month([DOB]) > 8, Year([DOB]) + 6 + [YearModifier], Year([DOB]) + 5 + [YearModifier])
My problem is that Year(Now()) is returning as invalid expression. Lots of websites have recognised using the Now() function and also I've tried Date() but nothing seems to be accepted by Access (The version is 2010).
What is going on? How can I get today's date in a calculated field expression?
Thanks
Try creating a query with all of the fields from your table, and then add an extra field YearGroup: Year(Now()) - IIf(Month([DOB]) > 8, Year([DOB]) + 6 + [YearModifier], Year([DOB]) + 5 + [YearModifier])
It appears that Date functions can't be used in calculated columns in tables.
You could use this to get the year, which might work in field expressions:
format(date(),"yyyy")
About your function (which I have re-written very slightly)
Year( Now() )
- Year([DOB])
- IIf( Month([DOB]) > 8
, 6
, 5 )
+ [YearModifier]
however!
I don't think you want to use now(). Which year they are in depend on their age at the 1st Sept at the start of the current academic year not now! Ok now will work until 31/dec/2015, so I must assume you will not be using the function after this date!
If you are you must use 2015 not Now().
Ok?
You can calculate the age of the children with a simple function:
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 your expression would be something like this (ignoring the modifier):
ClassYear: IIf(AgeSimple([DOB]) > 6, 2, 1)

Date Format changes when inserting into table if start date and end date cross one or more months

I have an Access 2013 form which has two unbound date fields, FromDate and ToDate. I insert these into a table (TblGuestBooking) which has an autonumber key field, so this doesn't feature in the SQL statement to follow.
If the FromDate and ToDate are in the same month, the dates are entered as dd/mm/yy, the format of the form field. If, however, the From date is in one month and the to date is in the next month or later month, the format changes to mm/dd/yy for the subsequent months.
for example 26/2/14 to 3/3/14 results in the following table entries:
26/02/14,
27/02/14,
28/02/14,
03/01/14,
03/02/14,
03/03/14
This is the code snippet I am using to put the dates into the table (BookingID is obtained from the form.)
Dim BookingDate As Date
Dim SQLString As String
....
BookingDate = FromDate
Do
SQLString = "INSERT INTO TblGuestBooking ([BookingDate], [BookingID]) VALUES (#" & BookingDate & "#" & "," & Me.GuestSuiteBookingID & ")"
DoCmd.SetWarnings False
DoCmd.RunSQL SQLString
DoCmd.SetWarnings True
BookingDate = BookingDate + 1
Loop Until BookingDate = ToDate + 1
If you've read this far, thank you for your time. If you can help me out, many, many thanks.
When processing date literals (text values enclosed by "hash marks" #) Access SQL will always interpret ambiguous xx-yy-zzzz dates as mm-dd-yyyy, regardless of the regional setting in place on the computer. So, if your machine is configured to display short dates as dd-mm-yyyy and you create an Access query that uses #04-02-2014# it will always be interpreted as April 2, not February 4.
The solution is to always format date literals as unambiguous yyyy-mm-dd values. In your case, instead of
... VALUES (#" & BookingDate & "#" ...
you would use something like
... VALUES (#" & Format(BookingDate, "yyyy-mm-dd") & "#" ...
In my case I've used following code for an ASP page that create and update a Date field in Access database.
strDay = Request("Day")
strMonth = Request("Month")
strYear = Request("Year")
InputDate = strYear & "-" & strMonth & "-" & strDay
if IsDate(InputDate) Then
InsertDate = CDate(InputDate)
else
'if date typed wrong, use Todays Date
InsertDate = Date()
end if
SQLUPD = "UPDATE MyDataBase SET DateField = '"& FormatDateTime(InsertDate, vbShortDate) &"'"
SQLINS = "INSERT INTO MyDataBase (DateField, Alist, Atype, Acomment) VALUES ('"& FormatDateTime(InsertDate, vbShortDate) &"', .....
Then all sorting and output opration with dates are going well.

Problem when extracting year and week number from string in PSQL

Let's say that I have a range of SQL tables that are named name_YYYY_WW where YYYY = year and WW = week number. If I call upon a function that guides a user defined date to the right table.
If the date entered is "20110101":
SELECT EXTRACT (WEEK FROM DATE '20110101') returns 52 and
SELECT EXTRACT (YEAR FROM DATE '20110101') returns 2011.
While is nothing wrong with these results I want "20110101" to either point to table name_2010_52 or name_2011_01, not name_2011_52 as it does now when I concanate the results to form the query for the table.
Any elegant solutions to this problem?
The function to_char() will allow you to format a date or timestamp to output correct the iso week and iso year.
SELECT to_char('2011-01-01'::date, 'IYYY_IW') as iso_year_week;
will produce:
iso_year_week
---------------
2010_52
(1 row)
You could use a CASE:
WITH sub(field) AS (
SELECT CAST('20110101' AS date) -- just to test
)
SELECT
CASE
WHEN EXTRACT (WEEK FROM field ) > 1 AND EXTRACT (MONTH FROM field) = 1 AND EXTRACT (DAY FROM field) < 3 THEN 1
ELSE
EXTRACT (WEEK FROM field)
END
FROM
sub;

How can I compare two datetime fields but ignore the year?

I get to dust off my VBScript hat and write some classic ASP to query a SQL Server 2000 database.
Here's the scenario:
I have two datetime fields called fieldA and fieldB.
fieldB will never have a year value that's greater than the year of fieldA
It is possible the that two fields will have the same year.
What I want is all records where fieldA >= fieldB, independent of the year. Just pretend that each field is just a month & day.
How can I get this? My knowledge of T-SQL date/time functions is spotty at best.
You may want to use the built in time functions such as DAY and MONTH. e.g.
SELECT * from table where
MONTH(fieldA) > MONTH(fieldB) OR(
MONTH(fieldA) = MONTH(fieldB) AND DAY(fieldA) >= DAY(fieldB))
Selecting all rows where either the fieldA's month is greater or the months are the same and fieldA's day is greater.
select *
from t
where datepart(month,t.fieldA) >= datepart(month,t.fieldB)
or (datepart(month,t.fieldA) = datepart(month,t.fieldB)
and datepart(day,t.fieldA) >= datepart(day,t.fieldB))
If you care about hours, minutes, seconds, you'll need to extend this to cover the cases, although it may be faster to cast to a suitable string, remove the year and compare.
select *
from t
where substring(convert(varchar,t.fieldA,21),5,20)
>= substring(convert(varchar,t.fieldB,21),5,20)
SELECT *
FROM SOME_TABLE
WHERE MONTH(fieldA) > MONTH(fieldB)
OR ( MONTH(fieldA) = MONTH(fieldB) AND DAY(fieldA) >= DAY(fieldB) )
I would approach this from a Julian date perspective, convert each field into the Julian date (number of days after the first of year), then compare those values.
This may or may not produce desired results with respect to leap years.
If you were worried about hours, minutes, seconds, etc., you could adjust the DateDiff functions to calculate the number of hours (or minutes or seconds) since the beginning of the year.
SELECT *
FROM SOME_Table
WHERE DateDiff(d, '1/01/' + Cast(DatePart(yy, fieldA) AS VarChar(5)), fieldA) >=
DateDiff(d, '1/01/' + Cast(DatePart(yy, fieldB) AS VarChar(5)), fieldB)
Temp table for testing
Create table #t (calDate date)
Declare #curDate date = '2010-01-01'
while #curDate < '2021-01-01'
begin
insert into #t values (#curDate)
Set #curDate = dateadd(dd,1,#curDate)
end
Example of any date greater than or equal to today
Declare #testDate date = getdate()
SELECT *
FROM #t
WHERE datediff(dd,dateadd(yy,1900 - year(#testDate),#testDate),dateadd(yy,1900 - year(calDate),calDate)) >= 0
One more example with any day less than today
Declare #testDate date = getdate()
SELECT *
FROM #t
WHERE datediff(dd,dateadd(yy,1900 - year(#testDate),#testDate),dateadd(yy,1900 - year(calDate),calDate)) < 0