Casting Strings into Birthdates (that aren't in the future) - sql

I am casting mm/dd/yy strings into dates in redshift using CAST AS DATE CAST(birth_str AS DATE) AS birth_date. The conversion handles the components correctly but the year is being converted into future times whenever it falls below 1970. For example:
birth_str birth_date
07/19/84 1984-07-19
02/07/66 2066-02-07
06/24/84 1984-06-24
01/31/64 2064-01-31
12/08/62 2062-12-08
02/21/36 2036-02-21
02/19/37 2037-02-19
07/01/74 1974-07-01
08/25/50 2050-08-25
08/31/39 2039-08-31
Is there a best practice for getting dates to not fall into the future?
Is there not an argument for this in the cast? (I looked everywhere but I am finding nothing.) Otherwise, I am envisioning the best path forward is testing for the cast date being in the future and then just doing string surgery on the miscreants before recasting them into reasonable dates.
Basically:
if not future date: great.
if future date:
peel out all the date components
slap a 19 onto the yy
glue everything back together
cast into date.
Is this as good as it gets? (I was a bit surprised I could find no one has come up with a better way around this issue already.)

Is there a best practice? Absolutely! Don't store dates as strings. Store dates as date. That is why SQL has native types.
In your case, you could use conditional logic:
select (case when cast(birth_str AS DATE) < current_date
then cast(birth_str AS DATE)
else cast(birth_str AS DATE) - interval '100 year'
end) as birth_date
Or since Redshift can't handle intervals you can go with this:
SELECT (CASE
WHEN birth_str::DATE < CURRENT_DATE
THEN birth_str::DATE
ELSE ADD_MONTHS(birth_str::DATE, -1200)
END) AS birth_date

You can apply a CASE to check the converted DATE IS greater than TODAY or not. If Yes, Just minus 100 years from the results as below.
One Question: Is there any chance of having dates like 02/21/14 which can be belongs to 1900 or 2000?
SELECT
CASE
WHEN CAST('02/21/36' AS DATE) >GETDATE() THEN DATEADD(YY,-100,CAST('02/21/36' AS DATE))
ELSE CAST('02/21/36' AS DATE)
END

Related

Case expression - comparing dates

I am using the query below, if the deadline column (eh.Deadline) < today (getdate) then returns 1, else 0.
(case when he.Deadline < CONVERT(VARCHAR(10),GETDATE(),111) then 1 else 0 end) Deadline
Everything works fine, but I need to change it so that only the month and the year (not the day), are compared.
Example, if Deadline=10/01/2022 and today=11/01/2022
My query returns 1 (10/01/2022 < 11/01/2022)
I would like to compare only the month and the year - I would like it to return 0 as MM/YYYY it's the same (01/2022 = 01/2022)
EDIT:
The column he.Deadline has the following format: DD/MM/YYYY HH/MM and this could not be compared to GETDATE and to solve that I had to use CONVERT(VARCHAR(10),GETDATE(),111) instead of GETDATE
The above query is used for a dashboard I created, and I wouldn't want to change anything in the database.
All I want is to compare MM/YYYY instead of DD/MM/YYYY
Any ideas please?
Thank you very much!
you could do (case when EOMONTH(he.Deadline) < EOMONTH(GETDATE()) then 1 else 0 end) Deadline
set the date to last day of the month for both values before comparing them so only the month/year will matter in the end
edit: as long as Deadline is a date... if it isn't then you have to convert it to date before calling EOMONTH on it
Firstly you need to ensure you are comparing a datetime/date with a datetime/date not a string with a datetime, nor a string with a string, as the comparisons are different all different, and your desired result is comparing a date.
Then you should be storing your data in the correct datatype, which for a datetime is a datetime2. Storing your Deadline as a string is going to cause you pain and trouble for the life of the project and will perform badly.
However with the situation as it is, you need to first convert your Deadline column correctly into a date value, and then secondly one way to solve your actual problem is to compare to the first of the current month as follows:
select
-- Convert to a date datatype in order to be able to correctly compare to another date
convert(date,substring(he.Deadline,1,10),103) -- Ensure dd/mm/yyyy as opposed to mm/dd/yyyy
<
-- Calculate the first of the month and check whether the Deadline is before then
convert(date,dateadd(day, -1*(datepart(day,getdate())-1), getdate())) then 1 else 0 end Deadline
from (
values ('10/01/2022 12/30')
) he (Deadline)

Format int as date in presto SQL

I have an integer date column "date_created" storing values like...
20180527, 20191205, 20200208
And am wondering what the best way to parse as a date is so I could do something like this in a query...
select * from table where formatted(date_created) > formatted(date_created) - 90
(to return everything within the last 90 days)
I've found some similar examples that convert from date ints representing seconds or milliseconds, but none where the columns are essentially date strings stored as integers.
Appreciate any thoughts on the best way to achieve this
And am wondering what the best way to parse as a date is so I could do something like this in a query...
You can convert "date as a number" (eg. 20180527 for May 27, 2018) using the following:
cast to varchar
parse_datetime with appropriate format
cast to date (since parse_datetime returns a timestamp)
Example:
presto> SELECT CAST(parse_datetime(CAST(20180527 AS varchar), 'yyyyMMdd') AS date);
_col0
------------
2018-05-27
However, this is not necessarily the best way to query your data. By adapting your search conditions to the format of your data (and not vice versa), you can potentially benefit from predicate push down and partition pruning. See #GordonLinoff answer for information how to do this.
You can do the comparison in the world of integers or of dates. You might as well convert the current date minus 90 days to a number:
select t.*
from t
where date_created >= cast(date_format(current_date - interval '90 day',
'%Y%m%d'
) as int
);
the below query is index friendly for any database since it does not use function on indexed column
select * from table where date_created > timestamp (formatted(date) - 90)
In addition, suppose we have date in format 20211011_1234 and we want one month older date and want back the original format, we can use the following formatting to convert date to int and vice versa.
select cast(date_format(
CAST(parse_datetime(cast(
split_part('20211011_1234', '_', 1) as varchar), 'yyyyMMdd')
AS date) - interval '30' day ,'%Y%m%d') as int) as column_name

Find record between two dates

When I write below query it gives record .
SELECT [srno],[order_no],[order_date],[supplier_name],[item_code],[item_name],[quntity]
FROM [first].[dbo].[Purchase_Order]
WHERE order_date BETWEEN '22/04/2015' AND '4/05/2015'
In this query if I don't add 0 in '4/05/2015' it returns record.
But when I add 0 to the date i.e. '04/05/2015' it doesn't give any records.
SELECT [srno],[order_no],[order_date],[supplier_name],[item_code],[item_name],[quntity]
FROM [first].[dbo].[Purchase_Order]
WHERE order_date BETWEEN '22/04/2015' AND '04/05/2015'
The reason it's not working because SQL is trying to do a string comparison because both your types are string types, But what you really want to do a date comparison.
You should do something like this. Since you only need date part you can strip off the time and use style 103 for your format dd/mm/yyyy.
WHERE CONVERT(DATETIME,LEFT(order_date,10),103)
BETWEEN CONVERT(DATETIME,'20150422') AND CONVERT(DATETIME,'20150504')
Alternately you can use this as well if your order_date has dates like this 5/4/2015 03:20:24PM
WHERE CONVERT(DATETIME,LEFT(order_Date,CHARINDEX(' ', order_Date) - 1),103)
BETWEEN CONVERT(DATETIME,'20150422') AND CONVERT(DATETIME,'20150504')
A long term solution is to change your column order_date to DATE/DATETIME
It Better to Cast it to date rather than depend on IMPLICIT conversion
SELECT [srno],[order_no],[order_date],[supplier_name],[item_code],
[item_name],[quntity] FROM [first].[dbo].[Purchase_Order] where
convert(date,order_date,105) BETWEEN cast('22/04/2015' as Date) AND cast('04/05/2015' as date)

How can I return data in a SQLite result set based on date range? [duplicate]

I can't seem to get reliable results from the query against a sqlite database using a datetime string as a comparison as so:
select *
from table_1
where mydate >= '1/1/2009' and mydate <= '5/5/2009'
how should I handle datetime comparisons to sqlite?
update:
field mydate is a DateTime datatype
To solve this problem, I store dates as YYYYMMDD. Thus,
where mydate >= '20090101' and mydate <= '20050505'
It just plain WORKS all the time. You may only need to write a parser to handle how users might enter their dates so you can convert them to YYYYMMDD.
SQLite doesn't have dedicated datetime types, but does have a few datetime functions. Follow the string representation formats (actually only formats 1-10) understood by those functions (storing the value as a string) and then you can use them, plus lexicographical comparison on the strings will match datetime comparison (as long as you don't try to compare dates to times or datetimes to times, which doesn't make a whole lot of sense anyway).
Depending on which language you use, you can even get automatic conversion. (Which doesn't apply to comparisons in SQL statements like the example, but will make your life easier.)
I had the same issue recently, and I solved it like this:
SELECT * FROM table WHERE
strftime('%s', date) BETWEEN strftime('%s', start_date) AND strftime('%s', end_date)
The following is working fine for me using SQLite:
SELECT *
FROM ingresosgastos
WHERE fecharegistro BETWEEN "2010-01-01" AND "2013-01-01"
Following worked for me.
SELECT *
FROM table_log
WHERE DATE(start_time) <= '2017-01-09' AND DATE(start_time) >= '2016-12-21'
Sqlite can not compare on dates. we need to convert into seconds and cast it as integer.
Example
SELECT * FROM Table
WHERE
CAST(strftime('%s', date_field) AS integer) <=CAST(strftime('%s', '2015-01-01') AS integer) ;
I have a situation where I want data from up to two days ago and up until the end of today.
I arrived at the following.
WHERE dateTimeRecorded between date('now', 'start of day','-2 days')
and date('now', 'start of day', '+1 day')
Ok, technically I also pull in midnight on tomorrow like the original poster, if there was any data, but my data is all historical.
The key thing to remember, the initial poster excluded all data after 2009-11-15 00:00:00. So, any data that was recorded at midnight on the 15th was included but any data after midnight on the 15th was not.
If their query was,
select *
from table_1
where mydate between Datetime('2009-11-13 00:00:00')
and Datetime('2009-11-15 23:59:59')
Use of the between clause for clarity.
It would have been slightly better. It still does not take into account leap seconds in which an hour can actually have more than 60 seconds, but good enough for discussions here :)
I had to store the time with the time-zone information in it, and was able to get queries working with the following format:
"SELECT * FROM events WHERE datetime(date_added) BETWEEN
datetime('2015-03-06 20:11:00 -04:00') AND datetime('2015-03-06 20:13:00 -04:00')"
The time is stored in the database as regular TEXT in the following format:
2015-03-06 20:12:15 -04:00
Right now i am developing using System.Data.SQlite NuGet package (version 1.0.109.2). Which using SQLite version 3.24.0.
And this works for me.
SELECT * FROM tables WHERE datetime
BETWEEN '2018-10-01 00:00:00' AND '2018-10-10 23:59:59';
I don't need to use the datetime() function. Perhaps they already updated the SQL query on that SQLite version.
Below are the methods to compare the dates but before that we need to identify the format of date stored in DB
I have dates stored in MM/DD/YYYY HH:MM format so it has to be compared in that format
Below query compares the convert the date into MM/DD/YYY format and get data from last five days till today. BETWEEN operator will help and you can simply specify start date AND end date.
select * from myTable where myColumn BETWEEN strftime('%m/%d/%Y %H:%M', datetime('now','localtime'), '-5 day') AND strftime('%m/%d/%Y %H:%M',datetime('now','localtime'));
Below query will use greater than operator (>).
select * from myTable where myColumn > strftime('%m/%d/%Y %H:%M', datetime('now','localtime'), '-5 day');
All the computation I have done is using current time, you can change the format and date as per your need.
Hope this will help you
Summved
You could also write up your own user functions to handle dates in the format you choose. SQLite has a fairly simple method for writing your own user functions. For example, I wrote a few to add time durations together.
My query I did as follows:
SELECT COUNT(carSold)
FROM cars_sales_tbl
WHERE date
BETWEEN '2015-04-01' AND '2015-04-30'
AND carType = "Hybrid"
I got the hint by #ifredy's answer. The all I did is, I wanted this query to be run in iOS, using Objective-C. And it works!
Hope someone who does iOS Development, will get use out of this answer too!
Here is a working example in C# in three ways:
string tableName = "TestTable";
var startDate = DateTime.Today.ToString("yyyy-MM-dd 00:00:00"); \\From today midnight
var endDate = date.AddDays(1).ToString("yyyy-MM-dd HH:mm:ss"); \\ Whole day
string way1 /*long way*/ = $"SELECT * FROM {tableName} WHERE strftime(\'%s\', DateTime)
BETWEEN strftime('%s', \'{startDate}\') AND strftime('%s', \'{endDate}\')";
string way2= $"SELECT * FROM {tableName} WHERE DateTime BETWEEN \'{startDate}\' AND \'{endDate}\'";
string way3= $"SELECT * FROM {tableName} WHERE DateTime >= \'{startDate}\' AND DateTime <=\'{endDate}\'";
select *
from table_1
where date(mydate) >= '1/1/2009' and date(mydate) <= '5/5/2009'
This work for me

Getting specific date values in SQL

I need to perform a query in which a require date value to be current date(or specific date) - 7 days. I came across many solutions like these,
(SELECT CONVERT(VARCHAR(10),DATEADD(DD, DATEDIFF(DD, 0, GETDATE()), -7),120))
However, for getting a week's value, i found a similar solution from here.
SELECT CONVERT(varchar(25),PostDate,107) AS duration, count(*) AS posts
FROM MDBDetails
WHERE DATEDIFF(week, PostDate,GETDATE()) = 1
GROUP BY CONVERT(varchar(25),PostDate,107)
ORDER BY duration
But, a simple query like GETDATE() -7 or the below code seems to do the required job for me.
DECLARE #Date DATETIME = '12/25/13'
SELECT #Date-7
My question is that, isn't the above method of subtracting date with a numerical value a good practice?
Of course I get the use of DATEDIFF can be extended to specify months and years too. But, is the above method a good practice? Is it necessary to use only DATEDIFF method to get the exact date values? Are there any major drawbacks or differences when compared to the first two methods? (except for subtracting months and years).
You'd better use DATEADD function.
Because if one day you decide to change date type of your column from DATETIME or SMALLDATETIME to DATE there will be an error.
You cannot subtract days from DATE. You should only use DATEADD function instead.