I have a table like below :
[TMP_TBL]
(
...
[DT_REFUND] [varchar(20)] NULL,
[MSG_PROCESS] [nvarchar(max)] NULL,
...
)
and it contains data like this:
| DT_REFUND | MSG_PROCESS |
| A-BC---D | WRONG DATETYPE |
| 20180301 | NULL |
| 20180331 | NULL |
When I do a query like:
select *
from TMP_TBL
where isnull(MSG_PROCESS, '') = ''
everything goes fine.
But when I do query like:
select *
from TMP_TBL
where isnull(MSG_PROCESS, '') = ''
and convert(DATE, DT_REFUND) >= convert(DATE, '20180301');
I get an error:
Conversion failed when converting date and/or time from character string
Why did this happen, and how to fix it?
Thanks
Ideally you should have avoided using VARCHAR data type for dates.
For the current scenario, you can use TRY_CONVERT like following.
select *
from TMP_TBL
where isnull(MSG_PROCESS, '') = ''
and TRY_CONVERT(DATE, DT_REFUND) >= convert(DATE, '20180301');
As your date column is VARCHAR, so there is a possibility of having empty spaces also, to handle this you can try RTRIM function before converting to date like following.
TRY_CONVERT(DATE, RTRIM(DT_REFUND)) >= convert(DATE, '20180301');
First you check the value in the column is DATE format or other format, using ISDATE function. And compare with the date value.
If it is not in date format it returns NULL value.
Try this:
SELECT *
FROM TMP_TBL
WHERE ISNULL(MSG_PROCESS,'') = ''
AND CONVERT(DATE, CASE WHEN ISDATE(DT_REFUND)=1 THEN DT_REFUND ELSE NULL END) >= CONVERT(DATE, '20180301');
You just need to filter out null values and compared date via cast() or convert() function
select *
from TMP_TBL
where MSG_PROCESS is null and
cast(DT_REFUND as date) >= '20180301';
This assumes null value has always date as your sample data suggests
In other way, first you could check DT_REFUND has some kind of date format data via TRY_CONVERT() function. So, your where clause should do
where MSG_PROCESS is null and TRY_CONVERT(date, DT_REFUND) is not null and
cast(DT_REFUND as date) >= '20180301';
However, the above has some redundant filtration before cast so you could also express that as
where MSG_PROCESS is null and TRY_CONVERT(date, DT_REFUND) >= '20180301';
Related
I have a table with DateFrom column
it's an nvarchar col in the col I have data like that
01
02
10/10/2020
04
some strings and some DateTime values
I need to cast it to DateTime but only if it's a date if not then pull out the value like it is can is this possible?
thanks ...
a Simple Try cast should do the job here
DECLARE #Table TABLE (Val NVARCHAR(20))
INSERT INTO #Table
VALUES('1'),('2'),('10/10/2020'),('04')
SELECT
*,
TRY_CAST(Val AS DATE)
FROM #Table
Results
Something like this should work. It uses a CASE statement to check whether or not the value is a valid date and if so casts it to DATETIME, then converts it to VARCHAR (so dates and other values can be returned as the same column).
You can find other datetime to string styles here if you need them formatted differently:
https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver15
DECLARE #TempTable TABLE (Dt NVARCHAR(30))
INSERT INTO #TempTable
VALUES('1'),('2'),('10/10/2020'),('04'),('Jun 27 2021 12:22AM'),('Oct 12 2021 8:31PM')
SELECT
*,
CASE WHEN ISDATE(Dt) = 1 THEN Convert(VARCHAR, CAST(Dt AS DATETIME), 120) ELSE Dt END
FROM #TempTable
You can easily check this with the case statement.
Postgres example
select case when '12/12/2021' ~ '\d{2}\/\d{2}\/\d{4}' then 'this is the date' ELSE 'this is a string' end;
->this is the date
select case when 'some text' ~ '\d{2}\/\d{2}\/\d{4}' then 'this is the date' ELSE 'this is a string' end;
->this is a string
so you can use it like this
select case when fild_01 ~ '\d{2}\/\d{2}\/\d{4}' then TO_DATE(fild_01,'DD/MM/YYYY')::text ELSE fild_01 end from test_table;
as you can see, case construction can't generalize two different types of data, so I had to convert them to the same type of text
Use the TRY_CONVERT function, with style 107
SELECT TRY_CONVERT(datetime, 'Jun 27 2021 12:22AM', 107)
Result
2021-06-27 00:22:00.000
This returns a null if the value is not a date
You can choose according to your needs.
When you want to set default value:
SELECT IIF(ISDATE(Val) = 1 , Val,'YOUR_DEFAULT_VALUE')
Whent default value not matter (It will be NULL):
SELECT TRY_CAST(NULL AS DATE)
I have a table with a varchar column with different values in it. Some of the values in this column are in fact datetime stamp but written in varchar data type.
I wish to find entries which contain datetime AND are related to today.
So, my table is like this:
ID | column_x
---------------------
12 | apple
13 | 25.03.2018 14:13:58
14 | 05.10.2020 10:43:17
15 | 3620
The following query works
select [ID] ,[column_x],
CAST(CONVERT(DATETIME, [column_x] , 104) AS DATE) the_date
from [my_DB].[dbo].[my_table]
where (ISDATE([column_x])=1)
The result is like this:
ID | column_x | the_date
-------------------------------------------------
13 | 25.03.2018 14:13:58 | 2018-03-25
14 | 05.10.2020 10:43:17 | 2020-10-05
15 | 3620 | 3620-01-01
Now I want to expand the afformentioned query to find the entries that belong to today (2020.10.05)
The following query gives error:
select * from (
select [ID] ,[column_x],
CAST(CONVERT(DATETIME, [column_x] , 104) AS DATE) the_date
from [my_DB].[dbo].[my_table]
where (ISDATE([column_x])=1)
) s
where
(select CAST(CONVERT(DATETIME, s.[column_x] , 104) AS DATE))=
(SELECT CAST(GETDATE() AS DATE))
The error message is:
Conversion failed when converting date and/or time from character string.
I can't understand why I get this error while I have already chosen only entries that are datetime according to the SQL itself.
More strangely, the following query works fine and prints the output:
if
(select CAST(CONVERT(DATETIME, '05.10.2020 19:46:19' , 104) AS DATE))=
(SELECT CAST(GETDATE() AS DATE))
print 'condition is fulfileld'
Even replacing the date with the problematic number (3620) doesn't result in error. Just the condition is not met in that case.
I can't understand why I get that error.
You can use try_convert() . . . but why not convert the current date to the same format:
select [ID] ,[column_x]
from [my_DB].[dbo].[my_table]
where left(column_x, 10) = convert(varchar(10), getdate(), 104)
To do the comparison the other way:
where try_convert(date, column_x, 104) = convert(date, getdate())
I am converting two Date columns to find the most recent one
SELECT ISNULL(CONVERT(varchar(10),REPLACE('10-07-2015','/','-'), 103),'01-01-1900'),
ISNULL(CONVERT(varchar(10),REPLACE('10/7/2015','/','-'), 103),'01-01-1900'),
CASE
WHEN ISNULL(CONVERT(varchar,REPLACE('10-07-2015','/','-'), 103),'01-01-1900') = ISNULL(CONVERT(varchar,REPLACE('10/7/2015','/','-'), 103),'01-01-1900')
THEN '10-07-2015'
END
My issue is some dates missing leading Zero in Day or Month and comparison is giving false results. Is there a better way to handle this? Other issue is one column has date with '/' and other have with '-'
Currently case is only checking on '=' but will add more to get the most recent
You can just convert those 2 varchars to the DATE type, then compare them.
You can find the date/datetime styles here
For those DD/MM/YYYY datestamps the 103 style would fit.
And to calculate the most recent between them, just wrap it in a CASE.
Example snippet:
declare #T table (
id int identity(1,1) primary key,
datestamp1 varchar(10),
datestamp2 varchar(10)
);
insert into #T (datestamp1, datestamp2) values
('5/9/2018','17/9/2018')
,('9-10-2018','16-10-2018')
,('15-10-2018','13-10-2018')
;
SELECT *,
TRY_CONVERT(DATE, datestamp1, 103) as date1,
TRY_CONVERT(DATE, datestamp2, 103) as date2,
CASE
WHEN TRY_CONVERT(DATE, datestamp1, 103) >= TRY_CONVERT(DATE, datestamp2, 103) THEN datestamp1
WHEN TRY_CONVERT(DATE, datestamp2, 103) IS NULL THEN datestamp1
ELSE datestamp2
END AS MostRecentDatestamp
FROM #T;
Returns:
id datestamp1 datestamp2 date1 date2 MostRecentDatestamp
1 5/9/2018 17/9/2018 2018-09-05 2018-09-17 17/9/2018
2 9-10-2018 16-10-2018 2018-10-09 2018-10-16 16-10-2018
3 15-10-2018 13-10-2018 2018-10-15 2018-10-13 15-10-2018
I have this rather complex query:
SELECT distinct
v.KodQ, v.DodPeriodika,
v.GodGP, v.Periodika as Period,
k.Oblast, k.KratokNazivSI,
k.NazivSI, k.Periodika,
v.rKod, r.Naziv,
v.rDatum,
v.IT, v.Primerok, v.BrojIE,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
FROM GP.dbo.MyTable1 AS v
INNER JOIN GP.dbo.MyTable2 as k
ON k.KodSI = v.KodQ AND k.DodObr = v.DodPeriodika
INNER JOIN GP.dbo.MyTable3 AS r
ON r.rKod = v.rKod
WHERE v.GodGP = GodGP and CHARINDEX('-', RefPeriodDo, 0) != 0
I need to convert v.RefPeriodOd and v.RefPeriodDo from this format '31-Dec-2017' to this format '31/12/2017'.
Yes I know saving DateTime as string(varchar) is bad idea, but the application is now in use so I cannot really do QA at the moment and refactor my table.
I am using this statement:
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
But the problem is, v.RefPeriodOd and v.RefPeriodDo can have a NULL values and also values in the format: '31/12/2017'
If I remove this condition:
CHARINDEX('-', RefPeriodDo, 0) != 0
I get this error:
The conversion of a nvarchar data type to a datetime data type
resulted in an out-of-range value.
How can I add some conditions in the query?
Does IF statement exists in TSQL?
Change
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd
for
CASE
WHEN CHARINDEX('-', RefPeriodDo, 0) != 0
THEN CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103)
END as RefPeriodOd
And remove the filter in the WHERE.
"IFs" are expressed with the CASE clause if inside SELECT statements, and the most common syntax is the following:
CASE
WHEN 1stCondition THEN 1stValue
WHEN 2ndCondition THEN 2ndValue
ELSE DefaultValue -- Else is optional
END
Conditions are evaluated in order, and if no ELSE is issued, then NULL is returned.
Try to add to the where the following:
WHERE (v.RefPeriodOd is not null and v.RefPeriodOd <> '')
AND (v.RefPeriodDo is not null and v.RefPeriodDo <> '')
Note:
You cannot put the condition in the WHERE clause. The filtering is not necessarily before the expressions in the SELECT.
You should always include a length for strings in SQL Server.
The right way to handle this is try_convert():
TRY_CONVERT(varchar(255), TRY_CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd,
TRY_CONVERT(varchar(255), TRY_CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
TRY_CONVERT() is available since SQL Server 2012. Before that, you needed to use a CASE to avoid conversion errors.
In my opinion, the filter condition should be:
RefPeriodDo LIKE '%-%'
I think this is easier to write and to read.
Try this:
SELECT distinct
v.KodQ, v.DodPeriodika,
v.GodGP, v.Periodika as Period,
k.Oblast, k.KratokNazivSI,
k.NazivSI, k.Periodika,
v.rKod, r.Naziv,
v.rDatum,
v.IT, v.Primerok, v.BrojIE,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodOd), 103) as RefPeriodOd,
CONVERT(varchar, CONVERT(DATETIME, v.RefPeriodDo), 103) as RefPeriodDo
FROM GP.dbo.MyTable1 AS v
INNER JOIN GP.dbo.MyTable2 as k
ON k.KodSI = v.KodQ AND k.DodObr = v.DodPeriodika
INNER JOIN GP.dbo.MyTable3 AS r
ON r.rKod = v.rKod
WHERE v.GodGP = GodGP AND ISNULL(v.RefPeriodOd,'')<>'' AND ISNULL(v.RefPeriodDo,'')<>''
Filter the rows using WHERE:
WHERE v.GodGP = GodGP AND ISNULL(v.RefPeriodOd,'')<>'' AND ISNULL(v.RefPeriodDo,'')<>''
Give this as try
Note the double use of 103
declare #D table (id int identity primary key, dt varchar(20));
insert into #D (dt) values (null), ('messy'), ('31-Dec-2017'), ('31/12/2017'), ('1/12/2017');
select d.dt
, TRY_CONVERT(DATETIME, d.dt, 103) as dt103
, isnull(TRY_CONVERT(varchar(20), TRY_CONVERT(DATETIME, d.dt, 103), 103), d.dt) dt103var
from #D d;
dt dt103 dt103var
-------------------- ----------------------- --------------------
NULL NULL NULL
messy NULL messy
31-Dec-2017 2017-12-31 00:00:00.000 31/12/2017
31/12/2017 2017-12-31 00:00:00.000 31/12/2017
1/12/2017 2017-12-01 00:00:00.000 01/12/2017
I have a table in which there is a column, ci_birthday. The column is declared as nvarchar(50), the format is mm-dd-yyyy. The data in the table is like this:
CI_BIRTHDAY
-----------
07/14/1956
NULL
NULL
11/01/1969
08/15/1955
07/08/1965
NULL
NULL
09/20/1936
NULL
NULL
NULL
NULL
0/0/0
NULL
NULL
NULL
NULL
NULL
0/0/0
NULL
NULL
1/29/1940
NULL
0/0/0
NULL
NULL
NULL
NULL
08/11/1949
I want the output from that column is only month and day, like
09/20
0/0
1/29
08/11
0/0
I accept my solution is a very bad way of solving this but if the date is not stored in a date format (in this case its a string), then you can do something like this:
DECLARE #Date varchar(15) = '11/01/1969'
SELECT SUBSTRING(#Date, 1,LEN(#Date) - PATINDEX('%/%',REVERSE(#Date)))
Just to show how to cast this very messy data into dates after checking it's safe to do so:
SET DATEFORMAT mdy;
WITH Dates
AS ( SELECT '07/14/1956' AS DateStr
UNION
SELECT '11/01/1969'
UNION
SELECT '08/15/1955'
UNION
SELECT '07/08/1965'
UNION
SELECT '09/20/1936'
UNION
SELECT '0/0/0'
UNION
SELECT NULL
UNION
SELECT '1/29/1940'
)
SELECT CASE WHEN ISDATE(DateStr) = 1 THEN CONVERT(VARCHAR(5), CONVERT(DATE, DateStr, 101), 101)
ELSE '00/00'
END AS [DD/MM]
FROM Dates