Difference Between two dates or N/A - sql

I have a calculation between two dates.
What I'm trying to do is if the start date is before 03/07/20 then show N/A otherwise the difference between the two dates
case
when StartDate < cast('03-07-20' as date) then
'N/A'
else
DATEDIFF(day, cast(StartDate as date), cast(SwabDate as date) )
end
as Days_From_First
I get
Conversion failed when converting the varchar value 'N/A' to data type int.
Warning: Null value is eliminated by an aggregate or other SET operation.
Thank you for your help

All branches of a case expression must return the same datatype, so you can't have a branch return a string ('NA') and the other a integer (as returned by datediff()). What happens when you do that is that SQL Server prioritizes the numeric datatype, and hence attempts to coerce 'NA' to an integer - which fails.
You could cast the return value of datediff() to a string - but I would not recommend that. Probably, using null is the best way to go here: in SQL, that's usually how we represent the absence of data:
case when StartDate >= '20200703'
then datediff(day, cast(startdate as date), cast(swabdate as date))
end as Days_From_First
Note that I changed the date comparison to use literal '20200703', that SQL Server is able to unambiguously understand as a date in format YYYYMMDD.

You need to cast the results to be strings:
(case when StartDate < cast('2020-03-07' as date)
then 'N/A'
else convert(varchar(255), datediff(day, cast(StartDate as date), cast(SwabDate as date) ))
end) as Days_From_First
That said, I would really suggest that you forget about 'N/A' and just use NULL.
Also, I don't know if your date is 2020-03-07 or 2020-07-03. That is why you should use standard date formats.

Related

Handling a value of zero in a date datatype

I'm reporting out of a database that is using decimal(17,6) as the datatype for a date field. For example, the current date/time in this field would be 20210820.171900. Unusual, but whatever. I need to convert the original date field from decimal(17,6) to datetime. This is what I have:
SELECT convert(datetime, convert(varchar,convert(int, lastmoddatetime)), 0)
from Table1
The above statement works correctly as long as none of the records have a value of zero in this column. Unfortunately, the column value defaults to zero (0.000000) if no date has been calculated for it. Whenever a column has a zero value, I get the following error:
Conversion failed when converting date from character string.
How can I overcome this issue? Ultimately, I'm needing to apply a dateadd function to the lastmoddatetime field.
Note: Before you suggest changing the column definition, this database originated in the 1990's and I'm not allowed to make any changes to the database structure.
You can use NULLIF to null out those values
convert(datetime, convert(varchar(15), convert(int, NULLIF(lastmoddatetime, 0.0))), 0)
Either use TRY_CONVERT or CASE - depending how you want to handle the zero case.
SELECT
-- If desiring null for 0 and SQL Server 2012+
TRY_CONVERT(date, CONVERT(varchar, CONVERT(int, lastmoddatetime)), 0)
, CASE WHEN lastmoddatetime <> 0
-- If desiring some other valid date or < SQL Server 2012
THEN CONVERT(date, CONVERT(varchar, CONVERT(int, lastmoddatetime)), 0)
ELSE NULL /* Whatever valid datetime value you want */ END
FROM (
VALUES (20210820.171900), (0.0)
) x (lastmoddatetime);
I note that this ignores the time component - so am converting to a date not datetime above. If you need to handle the time component you need to update your question.
Yet another option.
You can thin it out a bit by using left() and try_convert()
Example
Declare #YourTable table (lastmoddatetime numeric(17,6))
Insert into #YourTable values
(20210820.171900)
,(0.0)
Select AsDate = try_convert(date,left(lastmoddatetime,8))
,AsDateTime = try_convert(datetime,left(lastmoddatetime,8))
From #YourTable
Results
AsDate AsDateTime
2021-08-20 2021-08-20 00:00:00.000
NULL NULL
use
convert(datetime,convert(int,lastmoddatetime),0)

Why is '=' operator not working on comparing Datetime?

I am trying to fetch records only of the current day. I have used the = operator to compare the date but it is not working, if I subtract 1 from the current date and then use >= operator then it works.
I am putting both queries here.
This code works:
1 = (
CASE WHEN ISNULL(DO.CREATEDON, '') >= GETDATE()-1
THEN 1
END
This code doesn't work:
1 = (
CASE WHEN ISNULL(DO.CREATEDON, '') = GETDATE()
THEN 1
END
Why is the latter code not working?
GETDATE() returns a datetime, so (for me), right now, using GETDATE() returns something like 2021-01-19T09:43:27.123. It's therefore very unlikely the value in your column CREATEDON is going to be the same exact time that GETDATE() returns, accurate to the nearest 1/300 of a second.
If your column CREATEDON is a date and time value, use inclusive date ranges:
WHERE DO.CREATEDON >= CONVERT(date,GETDATE())
AND DO.CREATEDON < CONVERT(date,DATEADD(DAY, 1, GETDATE())
If CREATEDON is a date, then just CONVERT the value of GETDATE() to a date:
WHERE DO.CREATEDON = CONVERT(date,GETDATE())
Note that there's no need for the ISNULL, as is the value of NULL it is by definition not the value of GETDATE(). Also, converting'' to a date and time value is a little odd; but it would convert to 1900-01-01, which again, is not today. Adding an ISNULL on DO.CREATEDON in the WHERE will only harm the performance; don't do it.

Converting date and/or time from character string is failing

I have this query and I tried converting it to every format, I mean the date time etc but it doesn't work and throws error:
Conversion failed when converting date and/or time from character string.
SELECT W.Organization_ID,
W.NIT_No,
W.SchemeID,
OpeningDate,
OpeningTime,
GETDATE(),
WorkNo,
CONVERT(decimal(10, 2), W.Cost) AS Cost,
WorkName,
W.ExpiryDate as ExpiryDate,
CONVERT(VARCHAR,OpeningDate,106),
CASE WHEN
CONVERT(DATETIME, CONVERT(VARCHAR(20),OpeningDate,106) + ' '
+ CONVERT(VARCHAR(20),OpeningTime,108))< GETDATE()
THEN 1
ELSE 0 END AS OpeningVaild
FROM Works W
the CASE part throws error.
OpeningDate is of type Varchar and OpeningTime is of type Time.
Why?
You are converting just a TIME datatype not a DATETIME so you don't need to specify the style:
DECLARE #T TIME = '08:05:06';
SELECT CONVERT(VARCHAR(8), #T) AS [Time];
SELECT CAST(#T AS VARCHAR(8)) AS [Time];
Or since you are using CONVERT()pick the right style for TIME datatype which is 108 or 114, instead of 106
SELECT CONVERT(VARCHAR(8), #T, 108) AS [Time];
Update:
According to the error Msg, your problem is in the CASE part.
That because you are trying to concat a DATETIME with a VARCHAR datatype, look at here to what you'r converting:
CASE WHEN
CONVERT(DATETIME, CONVERT(VARCHAR(20),OpeningDate,106) + ' '
+ CONVERT(VARCHAR(20),OpeningTime,108))< GETDATE()
THEN 1
ELSE 0 END AS OpeningVaild
Also the column OpeningDate -according to the error Msg- is VARCHAR so your are convert a VARCHAR to VARCHAR then convert it again to DATETIME then you try to concatinate the DATETIME with the VARCHAR returned from converting OpeningTime column from TIMEto VARCHAR, then try to compare them with GETDATE() which is DATETIME datatype.
So you CASE should look like:
CASE WHEN
(
CAST(OpeningDate AS DATETIME) + -- VARCHAR to DATETIME
CAST(OpeningTime AS DATETIME) -- TIME to DATETIME
) < GETDATE()
THEN 1
ELSE 0 END AS OpeningVaild
A beside note, here in this line
CONVERT(VARCHAR,OpeningDate,106),
You are trying to convert a VARCHAR to VARCHAR and without specify the lenght too, so this line should be:
CONVERT(VARCHAR(10),CAST(OpeningDate AS DATE),106),
Finally, don't ever ever store DATE as VARCHAR, the DATE/ TIME/ DATEIME are there for a reason, so use them and all other datatypes wisely.
Here is a demo represent your issue, and how to fix it.
You can simplify this big time by changing the expression a little.
This way you don't have to convert and concatenate.
SELECT
CASE WHEN OpeningDate < GETDATE() - OpeningTime
THEN 1
ELSE 0 END AS OpeningVaild
Note I am assuming that Openingdate has the format dd-mon-yyyy. Otherwise you still need to convert it, but still shorter:
SELECT
CASE WHEN Convert(date, OpeningDate, 106) < GETDATE() - OpeningTime
THEN 1
ELSE 0 END AS OpeningVaild
So I understand the problem is with this part:
CASE WHEN CONVERT(DATETIME, CONVERT(VARCHAR(20),OpeningDate,106) + ' ' + CONVERT(VARCHAR(20),OpeningTime,108))< GETDATE() THEN 1 ELSE 0 END AS OpeningVaild
Update
Since I've first posted my answer it turns out that you store the opening date as varchar instead of date.
First, you should stop doing that. Never store dates in anything other than a Date column (unless you need them with time as well, and then use DateTime2).
For more information, read Aaron Bertrand's Bad habits to kick : choosing the wrong data type.
Assuming the data type of the column can't change, you wrote in the comments to the question:
#ZoharPeled: this is the format of openingdate 2017-04-10
Illustrating one of the problems caused by storing dates as strings - How can I, or anyone else for that matter, know if that's the 10th of April or the 4th of October? The answer is we can't.
So, assuming it's the 10th of April, you can convert it to DateTime using convert with 126 as the style parameter:
CASE
WHEN CONVERT(DateTime, OpeningDate, 126) + CAST(OpeningTime As DateTime) < GETDATE() THEN
1
ELSE
0
END As OpeningVaild
First version:
Assuming that the data type of OpeningDate is Date and the data type of OpeningTime is Time, Seems like you are attempting to figure out if these columns combination into a DateTime is before the current DateTime.
Instead of converting them into strings and back to DateTime, you can cast both to DateTime and simply add them together:
CASE
WHEN CAST(OpeningDate As DateTime) + CAST(OpeningTime As DateTime) < GETDATE() THEN
1
ELSE
0
END As OpeningVaild
Another option would be to use GETDATE() twice. I don't think it should matter in the select clause, but in the where clause it's important to use this option since the first one will make these columns non-seargable, meaning the database engine will not be able to use any indexes that might help the execution plan of the statement:
CASE
WHEN OpeningDate < CAST(GETDATE() AS DATE)
OR
(
OpeningDate = CAST(GETDATE() AS DATE)
AND OpeningTime <= CAST(GETDATE() AS TIME)
) THEN
1
ELSE
0
END AS OpeningVaild
That being said, your query also have CONVERT(VARCHAR,OpeningDate,106) - The 106 style returns a string representation of the date as dd mon yyyy - meaning 11 chars - so change that to CONVERT(CHAR(11),OpeningDate,106) Note that using varchar without specifying the length defaults to 30, which is not a problem in this case since it's more than he 11 chars you need, but it's a bad habit to not specify length and you should kick it.

Search date from SQL database from longer than one year ago

I have a SQL Database varchar field which is called date_finish. This field has been setup as a varchar(50). The format of the date is set out like this: 07/06/2017 dd/mm/yyyy.
I'm trying to search the database for all dates over 1 year old using this statement:
SELECT CONVERT(datetime, date_finish, 103) AS DB_DATE, booking_code, cust_id, status
FROM repair_details
WHERE (date_finish > DATEADD(year, - 1, GETDATE()))
ORDER BY DB_DATE
There are some fields that are blank, cust_id is 0 and status aren't complete, so I added:
(date_finish <> '') AND (status = 'COMPLETE') AND (cust_id <> '0')
to the above statement.
In all cases I get an error:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
What am I doing wrong???
Convert to a date using an explicit format:
WHERE CONVERT(date, date_finish, 103) > DATEADD(year, - 1, GETDATE())
Obviously, this gets dates since one year ago -- based on your code. If you want older dates, then use < rather than >.
Then, fix the data! You should be storing date/time values using proper types. One method is:
update repair_details
set date_finish = CONVERT(date, date_finish, 103); -- sets to default date format on system
alter repair_details alter date_finish date;
You haven't done the date conversion in the WHERE clause - it is comparing a string to a date there.
The error is because, when the column date_finish appears to be null. As such, you need to have a condition:
((date_finish IS NOT NULL ) AND
(date_finish <> '' ) ) AND
(status = 'COMPLETE' ) AND
(cust_id <> '0' )

Compare DATETIME and DATE ignoring time portion

I have two tables where column [date] is type of DATETIME2(0).
I have to compare two records only by theirs Date parts (day+month+year), discarding Time parts (hours+minutes+seconds).
How can I do that?
Use the CAST to the new DATE data type in SQL Server 2008 to compare just the date portion:
IF CAST(DateField1 AS DATE) = CAST(DateField2 AS DATE)
A small drawback in Marc's answer is that both datefields have been typecast, meaning you'll be unable to leverage any indexes.
So, if there is a need to write a query that can benefit from an index on a date field, then the following (rather convoluted) approach is necessary.
The indexed datefield (call it DF1) must be untouched by any kind of function.
So you have to compare DF1 to the full range of datetime values for the day of DF2.
That is from the date-part of DF2, to the date-part of the day after DF2.
I.e. (DF1 >= CAST(DF2 AS DATE)) AND (DF1 < DATEADD(dd, 1, CAST(DF2 AS DATE)))
NOTE: It is very important that the comparison is >= (equality allowed) to the date of DF2, and (strictly) < the day after DF2. Also the BETWEEN operator doesn't work because it permits equality on both sides.
PS: Another means of extracting the date only (in older versions of SQL Server) is to use a trick of how the date is represented internally.
Cast the date as a float.
Truncate the fractional part
Cast the value back to a datetime
I.e. CAST(FLOOR(CAST(DF2 AS FLOAT)) AS DATETIME)
Though I upvoted the answer marked as correct. I wanted to touch on a few things for anyone stumbling upon this.
In general, if you're filtering specifically on Date values alone. Microsoft recommends using the language neutral format of ymd or y-m-d.
Note that the form '2007-02-12' is considered language-neutral only
for the data types DATE, DATETIME2, and DATETIMEOFFSET.
To do a date comparison using the aforementioned approach is simple. Consider the following, contrived example.
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
CONVERT(char(8), OrderDate, 112) = #filterDate
In a perfect world, performing any manipulation to the filtered column should be avoided because this can prevent SQL Server from using indexes efficiently. That said, if the data you're storing is only ever concerned with the date and not time, consider storing as DATETIME with midnight as the time. Because:
When SQL Server converts the literal to the filtered column’s type, it
assumes midnight when a time part isn’t indicated. If you want such a
filter to return all rows from the specified date, you need to ensure
that you store all values with midnight as the time.
Thus, assuming you are only concerned with date, and store your data as such. The above query can be simplified to:
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
OrderDate = #filterDate
You can try this one
CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000')
I test that for MS SQL 2014 by following code
select case when CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000') then 'ok'
else '' end
You may use DateDiff and compare by day.
DateDiff(dd,#date1,#date2) > 0
It means #date2 > #date1
For example :
select DateDiff(dd, '01/01/2021 10:20:00', '02/01/2021 10:20:00')
has the result : 1
For Compare two date like MM/DD/YYYY to MM/DD/YYYY .
Remember First thing column type of Field must be dateTime.
Example : columnName : payment_date dataType : DateTime .
after that you can easily compare it.
Query is :
select * from demo_date where date >= '3/1/2015' and date <= '3/31/2015'.
It very simple ......
It tested it.....