SQL: Error when converting varchar to datetime - sql

WITH Valid_dates (ValidDate)
AS
(
SELECT '19' + SUBSTRING(column, 0, 3) + '-' + SUBSTRING(column, 3, 2) + '-' + SUBSTRING(column, 5, 2) AS ValidDate
FROM table
WHERE SUBSTRING(column, 3, 2) <= '12' --Max month
AND SUBSTRING(column, 3, 2) >= '01' --Min month
AND ISNULL(SUBSTRING(column, 3, 2), '') <> '' --Empty string
AND SUBSTRING(column, 5, 2) <= '31' --Max day
AND SUBSTRING(column, 5, 2) >= '01' --Min month
AND ISNULL(SUBSTRING(column, 5, 2), '') <> '' --Empty string
AND LEN('19' + SUBSTRING(column, 0, 3) + '-' + SUBSTRING(column, 3, 2) + '-' + SUBSTRING(column, 5, 2)) = 10 --Must match 10 character format
)
SELECT CONVERT(DATETIME, ValidDate)
FROM Valid_dates
When I execute this query in SQL Server Management Studio, I get the following error message: "The conversion of a varchar data type to a datetime data type resulted in an out-of-range value."
I have filtered out all invalid dates. Non-existent dates such as Feb 30, Apr 31, Jun 31 etc. are not filtered out per se as you can see, but I have checked for them, and they do not exist. Running only the CTE query yields plenty of results with which I can not find any discrepancies.

This is an issue with SQL Server. It does not guarantee the order of evaluation of clauses in the query. There is no sense that the where (even in the CTE) is evaluated "before" the rest of the query.
Note: This is a feature of the optimizer. By rearranging the evaluation of different components of the query, the optimizer can create a better query plan.
In SQL Server 2012+, the simplest method is TRY_CONVERT():
with . . .
select try_convert(datetime, validdate)
from valid_dates;
In earlier versions, you can use case:
select (case when <all your conditions here>
then convert(datetime, validdate)
end)
SQL Server does guarantee the sequential evaluation of case statements under normal circumstances (there are some quirky situations with aggregations), so this also fixes the problem.

I'm pretty sure that this is culture related.
You did not specify the actual input, from your code I suppose it is some unseparated format without a year like 920130 meaning the 30th of January in 1992?
This will be transformed in something like 1992-01-30.
Your default culture is probably one using something like yyyy-dd-mm which will lead into out-of-range error with a "month" higher than 12...
Try to use 102 as culture key:
SELECT CONVERT(DATETIME, ValidDate,102)
FROM Valid_dates
UPDATE
If my assumptions are true, it was much easier to try
SELECT TRY_CAST('19' + column AS DATE) FROM table
SQL Server allows natively to cast unseparated strings looking like yyyymmdd. Using TRY_CAST will return NULL if the cast is not possible.
With older versions (<2012) use this
SELECT CASE WHEN ISDATE('19' + column)=1 THEN CAST('19' + column AS DATE) ELSE NULL END FROM table

Related

Change nonth from 8 to 08 in SQL query

I am trying to get the month year from date that is in database.
I used the following query to get the date. But the formatting is not as I require. Due to this my query is not giving the result which I am expecting.
select top 3 datepart(yyyy, cia.DateCreated) as YYyy, datepart(mm, cia.DateCreated) as mm,
case when (datepart(mm, cia.DateCreated) < 10) then
cast(concat('0',datepart(mm, cia.DateCreated)) as varchar)
else
datepart(mm, cia.DateCreated)
end as Months
from v_AuthListInfo cia
I am getting the month values as 1, 2, 3, 4, 5, 6, 7, 8 but I need the value like 01, 02, 03, 04 ...
I tried to use DatePart, Cast and Concatinate function but still I am getting the data like 1, 2, 3, 4.
use right() function
RIGHT('0' + RTRIM(MONTH(cia.DateCreated)), 2);
You can use the built-in function format():
format(month(cia.DateCreated), '00')
If you want to use the right() method, I would suggest:
right(concat('00', month(cia.DateCreated)), 2)
Here's general approach how to pad with ceratin character:
right(#padding + cast(#stringToPad as varchar), 2)
where #padding consists of characters you want to use and its length has to be the desired length, so in your case it would be 00.
#stringToPad is string you want to extend, in your case cast(month(cia.DateCreated) as varchar).
So finally, giving an example, it would look like:
select right('00' + cast(1 as varchar), 2)

Convert nvarchar date (DD/MM/YYYY) to Date Period (YYYY_MM)

I am trying to convert this into a period format, so e.g. 2018_05 (YYYY_MM). currently the data is in DD/MM/YYYY format.
I tried a cast code but it returns me YYYY_DD.
SELECT
CASE WHEN RESERVED_FIELD_4 IS NULL THEN NULL
ELSE cast(year(RESERVED_FIELD_4) as Nvarchar (4))
+'_'+right('00'+cast(month(RESERVED_FIELD_4) as Nvarchar (2)),2)
END AS [DATAFEED_PERIOD]
I expect/want to see YYYY_MM.
Assuming RESERVED_FIELD_4 is a string type (char/nchar/varchar/nvarchar) the simplest solution would be to use substring:
CASE
WHEN RESERVED_FIELD_4 IS NULL THEN NULL
ELSE SUBSTRING(RESERVED_FIELD_4, 7, 4) + '_'+ SUBSTRING(RESERVED_FIELD_4, 4, 2)
END AS [DATAFEED_PERIOD]
If it's a date/datetime/datetime2 data type, the simplest solution would be to use format:
FORMAT(RESERVED_FIELD_4, 'yyyy_MM')
But for better performance you can use convert and stuff:
SELECT STUFF(CONVERT(char(6), RESERVED_FIELD_4, 112), 5, 0, '_')
In case your format is actually d/m/y the simplest option is to convert to date and than back to string:
SELECT STUFF(CONVERT(char(6), CONVERT(Date, RESERVED_FIELD_4, 103), 112), 5, 0, '_')
This is the common problem of storing a date with a VARCHAR column. You are guessing that the stored pattern is DD/MM/YYYY but the SQL engine doesn't know that and is currently assuming the MM/DD/YYYY pattern.
Please check these results:
-- MM/DD/YYYY
SELECT
DAY ('05/01/2019'), -- 1
MONTH('05/01/2019') -- 5
-- DD/MM/YYYY
SELECT
DAY ('25/05/2019'), -- Conversion failed when converting date and/or time from character string
MONTH('25/05/2019') -- Conversion failed when converting date and/or time from character string.
To display what you want correctly use string functions:
SELECT
RIGHT(RESERVED_FIELD_4, 4) + '_' + SUBSTRING(RESERVED_FIELD_4, 4, 2)
But you should actually fix the values on your VARCHAR column, cast them to DATE and store the values as DATE.
ALTER TABLE YourTable ADD ReservedField4Date DATE
UPDATE YourTable SET
ReservedField4Date = CONVERT(DATE,
RIGHT(RESERVED_FIELD_4, 4) -- Year
+ '-' + SUBSTRING(RESERVED_FIELD_4, 4, 2) -- Month
+ '-' + LEFT(RESERVED_FIELD_4, 2)) -- Day
ALTER TABLE YourTable DROP COLUMN RESERVED_FIELD_4
EXEC sp_rename 'SchemaName.YourTable.ReservedField4Date', 'RESERVED_FIELD_4', 'COLUMN'
Beware that changing the column type might affect other queries that assume this is a VARCHAR column.
If your data is in DD/MM/YYYY format, then it is being stored as a string. Hence, string functions come to mind:
select right(RESERVED_FIELD_4) + '_' + substrint(RESERVED_FIELD_4, 4, 2)
In SQL-SERVER you can use 'format'
format(dy,#your_date) as day_of_year
month(#your_date) as month
Try this:
Select concat(month(#your_date),'_'year(#your_date)) as your_period
this is a reference
Why not just do conversations ? :
SELECT REPLACE(CONVERT(VARCHAR(7), CONVERT(date, RESERVED_FIELD_4, 101), 102), '.', '_')
This assumes RESERVED_FIELD_4 is date type.

SQL Varchar convert to Date - Sybase

I am using Sybase IQ and have the following stored as a varchar:
01October 2010
I want to convert this from varchar to date datatype with the following format:
yyyy-mm-dd eg.2010-10-01
How would I write this SQL statement? Thanks in advance.
With difficulty. There's a reason you should never store dates and times as strings.
It's been awhile since I've used Sybase, but what we need to do is get the field into YYYY-MM-DD format, and then pass it to the DATE() or DATETIME() function.
Let's assume the first two characters are always the day of the month, and the last 4 characters are the year. That means everything in between is the month. Let's also assume that there are no leading or trailing spaces. If either of these assumptions fails, then the query will fail.
Then you can do something like this:
SELECT DATE (
RIGHT(UnnamedField,4) + '-' +
CASE LTRIM(RTRIM(SUBSTRING(Unnamed,3,LEN(Unnamed) - 6)))
WHEN 'January' THEN '01'
WHEN 'February' THEN '02'
WHEN 'March' THEN '03'
.
.
.
WHEN 'December' THEN '12'
END + '-' + LEFT(UnnamedField,2)
)
FROM UnnamedTable
Note that, as others have mentioned, the date data type is not a formatted datatype. If possible you should format it in your application. If you must do it in the query, use the CONVERT() function.
Sybase is able to convert a string to a date. So if you use substring to extract the date into a format that IQ can convert, then you can just use the convert() function.
Here's an example of how to do it:
Sample data:
create table #tmp1 (col1 varchar(100))
insert #tmp1 values ('01October 2010')
Query to convert the value to a date:
select
convert
(
date,
(
substring(col1, 3, charindex(' ', col1) - 2) -- Month
+ substring(col1, 1, 2) -- Day
+ substring(col1, charindex(' ', col1), 5) -- Year (include the leading space)
)
)
from #tmp1
Now that the value is in a date format, you can use the convert function to convert the date datatype to string, using your specified format. The default output for a date datatype is yyyy-mm-dd already.
Edit: After taking a look at #BaconBits' answer, I've realized that I could simplify the query a bit by using the substring function wrappers left, right, and the convert wrapper of date. It's the same logic; but using the simplified wrappers might make it easier to understand.
select
date
(
substring(col1, 3, charindex(' ', col1) - 2) -- Month
+ left(col1, 2) -- Day
+ ' ' + right(col1, 4) -- Year (include the leading space)
)
from #tmp1

query to search dates which are stored as string in the database

I have a table where I store an activity completion date as varchar. The format of the date stored is MM/DD/YYYY HH:MM:SS.
I have search window where I have two fields Completion date from and completion date to.The date format selected here is MM/DD/YYYY.
How do I write a query such that I am able to fetch the activity completion between two given dates from the table which has the dates stores as varchar.This table was created a long time back and no thought was given to saving dates as datetime.
You can use SQL CONVERT to change your columns to DATE format but that will cause performance issues.
SELECT *
FROM MyTable
WHERE CONVERT(DATETIME, MyDate) >= CONVERT(DATE, '01/01/2014')
AND CONVERT(DATETIME, MyDate) <= CONVERT(DATE, '01/31/2014')
CONVERT documentation - http://msdn.microsoft.com/en-us/library/ms187928.aspx
if you are unable to change how data is stored, than for better performance , you can create view with calculated column that converts VARCHAR to DATETIME. After that can create index on calculated column. Index on Computed Column documentation
Use the SUBSTRING function to get the date parts in a comparable order (i.e. yyyymmdd):
select *
from mytable
where
CONCAT( SUBSTRING(thedate, 7, 4) , SUBSTRING(thedate, 4, 2) , SUBSTRING(thedate, 1, 2) )
between
CONCAT( SUBSTRING(#FROMDATE, 7, 4) , SUBSTRING(#FROMDATE, 4, 2) , SUBSTRING(#FROMDATE, 1, 2) )
and
CONCAT( SUBSTRING(#TODATE, 7, 4) , SUBSTRING(#TODATE, 4, 2) , SUBSTRING(#TODATE, 1, 2) )
;
You could use this code :
select * from table_name
where CAST(col1 as date )
between CAST(Completion date from as date )
and CAST(Completion date to as date);
Function syntax CAST:
CAST ( expression AS data_type )
You can use below if the date format is {yyyy-MM-dd}, or you can adjust the charindex's index value depending on format
SELECT *
FROM table
WHERE
CHARINDEX('-', col_value, 0) = 5
AND CHARINDEX('-', col_value, 6) = 8
AND LEN(col_value) = 10
The above piece will look for first occurrence of char '-' at position 5 and the second char '-' at position 8 while the entire date value's length is equal to 10 chars
This is not full proof, but will narrow down the search. If you want to add time then just expand the criteria in the where to accommodate the format i.e. {yyyy-MM-dd 00:00:00.000}
This is a safe way to query the data, without any unexpected 'invalid cast / convert' errors.

How to convert a JDE date into a SQL date within a stored proceedure

I have been working on this for several days and tried all the options I could find. I am hoping that someone can clear this up. Within a stored proceedure I am pulling data from JDE into a SQL table. One of the fields is a JDE date field and I need this to go into a SQL table in the datetime format. The date field is IVEFTJ.
I have the follwoing:
SELECT DISTINCT * FROM OPENQUERY(GDCJDE9PRODR, '
SELECT
IVLITM,
IVCITM,
IVEFTJ,
Convert(datetime,DATEADD(day,[IVEFTJ]-729960,Convert(datetime,"1900-01-01")),103) as BCDAte
FROM
PRODDTA.F4104
WHERE
IVXRT = ''UP''
')
You can't use the SQL functions inside the openquery SQL statement, as this statement is relevant to the database you are selecting rows from. Rather, use the functions in the outer SQL statement, like this:
SELECT DISTINCT
IVLITM,
IVCITM,
IVEFTJ,
dateadd(day, convert(int, substring(IVEFTJ, 4, 3)), convert(datetime,convert(varchar(4), convert(int, substring(IVEFTJ, 1, 1))*100 + 1900 + convert(int, substring(IVEFTJ, 2, 2))) + '-01-01 00:00:00', 121)) as BCDAte
FROM OPENQUERY(GDCJDE9PRODR, '
SELECT
IVLITM,
IVCITM,
IVEFTJ,
IVEFTJ
FROM
PRODDTA.F4104
WHERE
IVXRT = ''UP''
')
Here is sqlfiddle for you to play with