How can I convert this INT field to a usable date field? - tsql

The DB I am working in stores their date values as INT. I am needing to determine a date difference between two date fields but am unsure how to approach this since they are currently INT.
Dates are stored as follows: 20130101 - YYYYDDMM. Performing a DATEDIFF results in an arithmetic overflow error.
Any ideas on how to either convert two date fields or to find the date difference between them?

Select Cast( Cast( 20130101 As varchar(8) ) As datetime )
So, if you have the following two values: 20130101, 20130201, we might do the following:
Select DateDiff( d
, Cast( Cast( 20130101 As varchar(8) ) As datetime )
, Cast( Cast( 20130201 As varchar(8) ) As datetime ) )
Update
If you have values that less than 17530101 (the min value for a datetime), then you will need to use a Case expression to validate the data as it is processed. In this scenario, the use of Cast(0 As datetime) will result in 1900-01-01 as our minimum date value.
Select DateDiff( d
, Case
When Value1 <= 19000101 Then Cast(0 As datetime)
Else Cast( Cast( Value1 As varchar(8) ) As datetime )
End
, Case
When Value2 <= 19000101 Then Cast(0 As datetime)
Else Cast( Cast( Value2 As varchar(8) ) As datetime )
End )
If you are going to store the dates as integers as shown, a better idea would be to correct the data and add a check constraint that prevents values lower than 1900-01-01. If you have legitimate values lower than 1900-01-01, that will require yet another adjustment to the solution.

Related

Can I throw an error in a computed column select case?

I have a "case when" in my computed column, but I can't figure out how to throw an exception.
Here's sample code that doesn't work...
CREATE TABLE OrderDetail
( OrderID INT
, ProductID INT
, Qty INT
, OrderDate DATETIME
, ShipDate DATETIME
, STATUS AS CASE
WHEN shipdate is NULL AND orderdate < DATEADD( dd, -7, GETDATE()) THEN 3
WHEN shipdate is NOT NULL THEN 2
ELSE RAISERROR ('Error in shipdate',-1,-1)
end
)
GO
But it is invalid.
Isn't it possible to raise an error in computed columns?
This can't be done like this. A case expression can't be used as a flow control. It's specifically documented:
The CASE expression cannot be used to control the flow of execution of Transact-SQL statements, statement blocks, user-defined functions, and stored procedures.
You can add a check constraint to the table, but that would not allow you to raise your own custom error:
CREATE TABLE OrderDetail
(
OrderID INT
, ProductID INT
, Qty INT
, OrderDate DATETIME
, ShipDate DATETIME
, STATUS AS CASE
WHEN shipdate is NULL AND orderdate < DATEADD( dd, -7, GETDATE()) THEN 3
WHEN shipdate is NOT NULL THEN 2
ELSE NULL
END
, CONSTRAINT Chk_OrderDetails_Dates CHECK(
shipdate IS NOT NULL
OR orderdate < DATEADD( dd, -7, GETDATE())
)
)
GO
Or you can use triggers - instead of insert and instead of update to only allow rows where the dates are valid.
Personally, I would go with a check constraint - It's safe and more easier to write and maintain.

T-SQL: Extract Substring

I have to read dates from a varchar column with the following possible patterns ( month/day/year ):
1/1/2005
1/13/2005
10/9/2005
10/13/2005
What is the correct way to read the day part of those dates with T-SQL?
Casting to date and using day() would be the correct approach imo:
declare #t table (string varchar(10))
insert #t values ('1/1/2005'),('1/13/2005'),('10/9/2005'),('10/13/2005')
select day(cast(string as date)) as the_day from #t
Would give:
the_day
-----------
1
13
9
13
An alternative if you want to avoid casting would be to use thesubstringandcharindexfunctions:
select
substring(
string,
charindex('/', string)+1,
charindex('/', string, charindex('/', string)+1)-charindex('/', string)-1
)
from #t

casting text to date in redshift

I have saved date as text type. There are a few invalid dates those are preventing me from running any date related operation. For e.g.
select case when deliver_date = '0000-00-00 00:00:00' then '2014-01-01' else deliver_date::date end as new_date, count(*) as cnt from some_table group by new_date
Error in query: ERROR: Error converting text to date
I am using the following work-around that seems to be working.
select left(deliver_date,10) as new_date, count(*) as cnt from sms_dlr group by new_date
But I will like to know if it is possible to convert this column to date.
You need to separate the valid and invalid date values.
One solution is to use regular expressions- I'll let you decide how thorough you want to be, but this will broadly cover date and datetime values:
SELECT
CASE
WHEN
deliver_date SIMILAR TO '[0-9]{4}-[0-9]{2}-[0-9]{2}'
OR deliver_date SIMILAR TO '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}'
THEN TO_DATE(deliver_date, 'YYYY-MM-DD')
ELSE TO_DATE('2014-01-01', 'YYYY-MM-DD')
END as new_date,
COUNT(*) as cnt
FROM some_table
GROUP BY new_date
Try dropping the ::date part:
select
cast(
case
when deliver_date = '0000-00-00 00:00:00' then '2014-01-01'
else deliver_date
end
as date
) as new_date,
count(*) as cnt
from some_table
group by new_date

Concatenate Date and Time Column of Character DataType Into DateTime DataType

Once I run the query how do I put them back together again?
I was able to run the following query to convert date value into datetime and append time part to it
declare #date char(8), #time char(8)
select #date='20101001',#time ='12:10:47'
select cast(#date as datetime)+#time
In the above method, date value is converted to datetime datatype and time value is
added to it.
--------------Output ----------------------
result tab -
(No column name )
row1 || 2011-09-16 22:16.000
How can I covert back to the original data Value(undo)??????
I ran the above query to converted to datetime datatype and time value is
added to it- worked well...Now I want to undo go back to the original date value.....
It is not clear what the question is but this is my guess. If you are trying to extract pieces of a datetime use the DatePart funciton,
declare #date char(8), #time char(8)
select #date='20101001',#time ='12:10:47'
select cast(#date as datetime)+#time
select cast(cast(#date as datetime)+#time as datetime)
select DATEPART(mm,cast(cast(#date as datetime)+#time as datetime))
To extract the constituent parts of a datetime into a string of a specific format use the CONVERT function and pass the desired style. To get back to where you started use
DECLARE #date CHAR(8),
#time CHAR(8)
SELECT #date = '20101001',
#time = '12:10:47'
DECLARE #dt DATETIME
SELECT #dt = CAST(#date AS DATETIME) + #time
SELECT CONVERT(CHAR(8), #dt, 112) AS [#date],
CONVERT(CHAR(8), #dt, 108) AS [#time]
Which gives
#date #time
-------- --------
20101001 12:10:47

How do I TryParse in SQL 2000?

I have a stored procedure in an old SQL 2000 database that takes a comment column that is formatted as a varchar and exports it out as a money object. At the time this table structure was setup, it was assumed this would be the only data going into this field. The current procedure functions simply this this:
SELECT CAST(dbo.member_category_assign.coment AS money)
FROM dbo.member_category_assign
WHERE member_id = #intMemberId
AND
dbo.member_category_assign.eff_date <= #dtmEndDate
AND
(
dbo.member_category_assign.term_date >= #dtmBeginDate
OR
dbo.member_category_assign.term_date Is Null
)
However, data is now being inserted into this column that is not parsable to a money object and is causing the procedure to crash. I am unable to remove the "bad" data (since this is a third party product), but need to update the stored procedure to test for a money parsable entry and return that.
How can I update this procedure so that it will only return the value that is parsable as a money object? Do I create a temporary table and iterate through every item, or is there a more clever way to do this? I'm stuck with legacy SQL 2000 (version 6.0) so using any of the newer functions unfortunately is not available.
Checking for IsNumeric may help you - you can simply return a Zero value. If you want to return a 'N/a' or some other string value
I created the sample below with the columns from your query.
The first query just returns all rows.
The second query returns a MONEY value.
The third one returns a String value with N/A in place of the non-integer value.
set nocount on
drop table #MoneyTest
create table #MoneyTest
(
MoneyTestId Int Identity (1, 1),
coment varchar (100),
member_id int,
eff_date datetime,
term_date datetime
)
insert into #MoneyTest (coment, member_id, eff_date, term_date)
values
(104, 1, '1/1/2008', '1/1/2009'),
(200, 1, '1/1/2008', '1/1/2009'),
(322, 1, '1/1/2008', '1/1/2009'),
(120, 1, '1/1/2008', '1/1/2009')
insert into #MoneyTest (coment, member_id, eff_date, term_date)
values ('XX', 1, '1/1/2008', '1/1/2009')
Select *
FROM #MoneyTest
declare #intMemberId int = 1
declare #dtmBeginDate DateTime = '1/1/2008'
declare #dtmEndDate DateTime = '1/1/2009'
SELECT
CASE WHEN ISNUMERIC (Coment)=1 THEN CAST(#MoneyTest.coment AS money) ELSE cast (0 as money) END MoneyValue
FROM #MoneyTest
WHERE member_id = #intMemberId
AND #MoneyTest.eff_date <= #dtmEndDate
AND
(
#MoneyTest.term_date >= #dtmBeginDate
OR
#MoneyTest.term_date Is Null
)
SELECT
CASE WHEN ISNUMERIC (Coment)=1 THEN CAST (CAST(#MoneyTest.coment AS money) AS VARCHAR) ELSE 'N/a' END StringValue
FROM #MoneyTest
WHERE member_id = #intMemberId
AND #MoneyTest.eff_date <= #dtmEndDate
AND
(
#MoneyTest.term_date >= #dtmBeginDate
OR
#MoneyTest.term_date Is Null
)
Apologies for making a new answer, where a comment would suffice, but I lack the required permissions to do so. Onto the answer to your question, I would only like to add that you should use the above ISNUMERIC carefully. While it works much as expected, it also parses things like '1.3E-2' as a value numeric, which strangely enough you cannot cast into a numeric or money without generating an exception. I generally end up using:
SELECT
CASE WHEN ISNUMERIC( some_value ) = 1 AND CHARINDEX( 'E', Upper( some_value ) ) = 0
THEN Cast( some_value as money )
ELSE Cast( 0 as money )
END as money_value