SQL Server DateTime cast from VarChar - sql-server-2008

I've got a table with 9 million records. Each one has a "BirthDate" field that is stored as a varchar. I'm trying to select all where the birthdate is 25 years or less (all people 25 or under). It's failing, because somewhere in this monstrosity of a table, there is an invalid value.
select COUNT(*) from LeadSplit where CAST(LeadSplit.Birthdate as datetime) > DATEADD(yy, -26, getdate()) and Birthdate is not null
The error is:
Msg 242, Level 16, State 3, Line 1
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
I'm at a loss as to how to find the row with the invalid value, and also, how to deal with it. I would like to just ignore it or fix it.

You could try to find the offending rows by doing something like:
SELECT (some ID), Birthdate
FROM dbo.YourTable
WHERE ISDATE(Birthdate) = 0
This might not work for all cases - but it might give you a starting point.

The error you are getting is that one or more of the dates cannot be parsed given the DateFormat setting.
Set DateFormat MDY
GO
Select Count(*)
From LeadSplit
Where Case
When IsDate(BirthDate) = 0 Then 0
When BirthDate >= DateAdd(yyyy,-25,CURRENT_TIMESTAMP) Then 1
End = 1

Try to use CONVERT instead of CAST and explicit specify date format. MSDN Article about CAST and CONVERT

Related

MySQL STR_TO_DATE Problem while using this function

As title, I'm trying to convert a VARCHAR column in a DATE column, and data is populated in that format "DDMMYYYY" ex. XMAS is "25122022" and in this case the correct formula should be STR_TO_DATE(column, '%d%m%Y')Well, when I execute this query I get an error since in some cases I have values with a "missing" char, I mean, for example, "1012023" when the day is <10 the query fails, cause it checks for "01122023" instead.I could solve this easily by adding a 0 to all fields having length 7, but I'd like to make it more clean.Reading better the usage of STR_TO_DATE I noticed that I could replace %d with %e since the second choice should theorically consider days from 0 to 31 instead of 01 to 31.Unexpectedly the query didn't work and gave me the same erorr at the first instance of a length 7 string.Am I doing something wrong?Thanks in advance.
We can try left padding your date string with zero to a length of 8:
WITH yourTable AS (
SELECT '1012023' AS dt
)
SELECT STR_TO_DATE(LPAD(dt, 8, '0'), '%d%m%Y') AS dt_out -- 2023-01-01
FROM yourTable;
Demo

Postgresql json field has dates in both YYYY-MM-DD and 13 digit unix timestamp format

I am parsing a json array and one field I am pulling out is closedate. However closedate has two different date formats one is YYYY-MM-DD and the other is a 13 digit timestamp. I am trying to get consistent formatting of the dates as well as have it be an integer compared to a string. Right now the query returning the close date is:
json_array_elements(ld.data->'Table1'->'Details')->>'closeDate' as closedate
and it returns close date as a string:
id
closedate
1
2021-09-29
2
1606824000000
Someone was telling me to do something like a case statement with regex. But I am not familiar with regex function. Any help is appreciated.
Edit: I have
case when x.closedate::text ~* '^[0-9]{13}$' then
to_timestamp(x.closedate::bigint/1000)
when x.closedate = '0' then null
when x.closedate = '' then null
else
to_date(x.closedate,'MMDDYYYY') end as transactionclosedate
the case statement works for converting the 13 digit timestamp to a date but I am getting the error:
ERROR: date/time field value out of range: "2020-10-23"
when trying to convert the date strings in the correct format to dates in the else part of the case statement.
An example of one way to make this work. My regex skills are not strong so others may have a better solution:
create table regex_test (id int, fld_1 varchar);
insert into regex_test values (1, '1606824000000'), (2, '2021-09-29');
select * from regex_test ;
id | fld_1
----+---------------
1 | 1606824000000
2 | 2021-09-29
select
id,
case when fld_1 ~* '^[0-9]*$' then
to_timestamp(fld_1::bigint/1000)
else
fld_1::timestamp end as ts_fld
from
regex_test;
id | ts_fld
----+------------------------
1 | 2020-12-01 04:00:00-08
2 | 2021-09-29 00:00:00-07
I hope this query help you
with data as (
select
json_array_elements(data->'Table1'->'Details')->>'closeDate' as closedate
from your_table
)
select
case when closedate::text ~ '^[0-9]+$' then
to_timestamp(closedate::numeric / 1000)::date
else
closedate::date
end
from data;
Either of the other answers would be ok providing that only the specified formats exist. However, containing those formats requires a text field; which may contain anything. It is dangerous to assume if the content is not 13 digits then it is a valid formatted ISO date. I would validate that as well (and verify digits length).
select id,
, case when closedate ~* '^[0-9]{13}$' then
to_timestamp(closedate::bigint/1000)
when is_valid_iso_date(closedate) then
closedate::timestamp
else
'-infinity'::timestamp -- or whatever to indicate Invalid Date.
from <your table> ;
The problem being that is_valid_iso_date function. It turns out however I had to create just that a couple years ago, I'll make the result available here.
DISCLAIMER: While the function has given no known erroneous results it has NOT been exhaustively tested.

How to avoid error on MYSQL CONVERT() method, when passing a 0 second string and subtract from that value?

I am using MySQL 8 and have a problem with this type of query:
INSERT INTO review (name, create_date) VALUES('name', CONVERT(timestamp, DATETIME) - 1)
I have not had this error when using this expression in a where clause.
When the value for the timestamp is like '2020-12-16 06:15:01' it's working.
But with a value of 0 seconds (like: '2020-12-16 06:15:00') an error is dropped.
Incorrect datetime value: '20201216061499' for column 'create_date' at row 1
code: ER_TRUNCATED_WRONG_VALUE
errno: 1292
sqlState: 22007
I used this type of expression in my whole project. Is there a simple solution to this problem, without changing each expression?
Is that one a bug?
One solution to this problem is:
DATE_SUB(CONVERT(timestamp,DATETIME) INTERVAL 1 SECOND).
But as I already mention this requires changing each expression.
You do need to update each expression. When you subtract a number from your timestamp, it first converts your timestamp into a number (e.g. 20201216061500), then you are subtracting one and, because the column you are inserting is a datetime, it tries to interpret the resulting number as a date/time, failing when the subtraction produced 20201216061499. The correct way to subtract one second is to say - INTERVAL 1 SECOND or use DATE_SUB(..., INTERVAL 1 SECOND).

Casting negative integer to DATE in SQL

I'm having a problem working with a Navicat Database. I got a column in SQL called fechaNacimiento (Birthdate) that should be a Date type, but instead it's stored as integers (most negative integers):
SELECT fechaNacimiento FROM Registrados
And I'm getting:
fechaNacimiento
-1451678400
-2082829392
-1798746192
-1199221200
-1356984000
-694299600
-1483214400
-1924976592
-1830368592
-2019670992
-1678909392
239252400
1451617200
-879541200
I don't know how this dates where loaded, I just know that inside that negative integer there's a date, and nobody here have any clue about how to spell SQL, so I have nobodoy to ask. If I just cast it to DATETIME, I get all of them as NULL values. Any idea in how to convert this data to Date type?
Numbers like that make me think of Unix times, number of seconds since 1970. If so, you might be able to do:
select dateadd(second, <column>, '1970-01-01')
This would put the negative values sometime before 1970 (for instance, -1678909392 is 1916-10-19). If you have older dates, then that might be the format being used.
These might also be represented as milliseconds. If so:
select dateadd(second, <column>/1000, '1970-01-01')
In this case, -1678909392 represents 1969-12-12.
In MySQL, you would use:
select '1970-01-01' + interval floor(column / 1000) second

MySQL does not convert string to int, despite casting it

So what I am trying to do is to substract number of week from date, easy, right?
However, query returns a string I believe, because no matter how I try to sort it, it still gets sorted in that order: 0, 1, 10, 11, 12, ... 19, 2, 21
Of course I have googled, I have already tried CAST AS SIGNED/UNSIGNED/INT/DECIMAL. I did try to FORMAT it, multiply by one, add zero to result - nothing happens.
I use my query in BIRT - as I have managed to get it sorted in BIRT table, it still gets scrumbled in Workbench and BIRT charts - and it makes them look like nonsense.
Now as I write this post I see that the problem is that I have CASE there:
SELECT CASE WHEN 2 = 1 THEN SUBSTR(mydate, 1, 7) ELSE CAST(WEEK(mydate, 0) AS SIGNED) END AS 'data' FROM mytable
Still: why does CAST not work when it's accompanied with CASE that might return a string? I wanted to conditionally let users choose whether the data is grouped by YYYY-MM (year and month) OR by weeks, now it seems I got kind of stuck.
That casting (CAST(WEEK(mydate, 0) AS SIGNED)) looks unnecessary to me since week() function returns week number in INT. So probably you can cast the result of week() to varchar since substring will result in varchar
CASE WHEN 2 = 1 THEN SUBSTR(mydate, 1, 7) ELSE CAST(WEEK(mydate, 0) AS CHAR(100)) END AS data
FROM mytable