Converting NVARCHAR to SMALLDATETIME on SQL SERVER 2008 - sql

I'm currently working on updating company database in which on one of the tables the CreateDt is in the nvarchar(20) type and stores dates in the following ways:
12 May 12
29/03/2011
9/24/2012
29/01/2001 08:51:56
There are 17,000 rows.
So I'm currently working on code in which I will be able to convert these dates all into the one format such as DD-MM-YYYY.
However I'm struggling to find anything suitable.
So far I have tried:
WITH CreateDt1
AS
(
SELECT '14 DECEMBER 12' AS CreateDt1
UNION ALL
SELECT '13/10/2005'
UNION ALL
SELECT '12/14/2012'
UNION ALL
SELECT '24/05/2002 09:28:58'
UNION ALL
SELECT '28/02/2011'
)
SELECT
CreateDt1,
CASE WHEN ISDATE(CreateDt1) = 1
THEN CAST(CreateDt1 AS datetime)
ELSE
CASE WHEN SUBSTRING(CreateDt1, 3, 1) = '/'
THEN
CASE WHEN ISDATE(SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1, 2) + '/' + RIGHT (CreateDt1, 4)) = 1
THEN CAST(SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1 , 2) + '/' + RIGHT (CreateDt1, 4) AS datetime)
END
END
END AS NewDate
FROM fct_Project;
However this returns null values for dates such as 29/01/2001 08:51:56.

Try add LEFT function in RIGHT to your query in case clause like:
CASE WHEN ISDATE(CreateDt1) = 1
THEN CAST(CreateDt1 AS datetime)
ELSE
CASE WHEN SUBSTRING(CreateDt1, 3, 1) = '/'
THEN
CASE WHEN ISDATE(SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1, 2) + '/' + RIGHT (LEFT(CreateDt1,10), 4)) = 1
THEN CAST(SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1 , 2) + '/' + RIGHT (LEFT(CreateDt1,10), 4) AS datetime)
END
END
END AS NewDate

I've just edited your code by adding a few lines, hope it will help.
Keep in mind, that it does not solve problem of 10/11 and 11/10 cases.
WITH CreateDt1
AS
(
SELECT '14 DECEMBER 12' AS CreateDt1
UNION ALL
SELECT '13/10/2005'
UNION ALL
SELECT '12/14/2012'
UNION ALL
SELECT '24/05/2002 09:28:58'
UNION ALL
SELECT '28/02/2011'
)
SELECT
CASE WHEN ISDATE(CreateDt1) = 1
THEN CAST(CreateDt1 AS datetime)
ELSE
CASE WHEN SUBSTRING(CreateDt1, 3, 1) = '/'
THEN
CASE WHEN ISDATE(SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1, 2) + '/' + RIGHT (CreateDt1, 4)) = 1
THEN CAST(SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1 , 2) + '/' + RIGHT (CreateDt1, 4) AS datetime)
WHEN ISDATE(SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1, 2) + '/' + LEFT((RIGHT (CreateDt1, 13)),4) ) = 1
THEN CAST ( (SUBSTRING(CreateDt1, 4, 2) + '/' + LEFT(CreateDt1, 2) + '/' + LEFT((RIGHT (CreateDt1, 13)),4) ) AS DATETIME)
END
END
END AS NewDate
FROM CreateDt1;

Related

How do you do a where clause with a select statement as a value

I'm trying to get the total amount from the next month's record.
SELECT TOP (1000)
[DEMAND_POINT_ID],
[DPM_XREF_ID],
[UTIL_TYPE],
[ACCOUNT_ID],
[REV_YR_MNTH],
[TOTAL_AMOUNT],
(SELECT CAST(LEFT((SELECT CONVERT(varchar, DATEADD(month, 1, LEFT(REV_YR_MNTH, 4) + '-' + RIGHT(REV_YR_MNTH, 2) + '-' + '01'), 112)), 6) AS int)) AS nextmonth,
(SELECT de2.[TOTAL_AMOUNT]
FROM [DEQEnergyUsage].[dbo].[DST_ENERGY_USAGE_AGGR] de2
WHERE de2.ACCOUNT_ID = de.ACCOUNT_ID
AND de2.REV_YR_MNTH = (SELECT CAST(LEFT((SELECT CONVERT(varchar, DATEADD(month, 1, LEFT(REV_YR_MNTH, 4) + '-' + RIGHT(REV_YR_MNTH, 2) + '-' + '01'), 112)), 6) AS int))) AS nextamount
FROM
[DEQEnergyUsage].[dbo].[DST_ENERGY_USAGE_AGGR] de
WHERE
ACCOUNT_ID =1
ORDER BY
ACCOUNT_ID, de.REV_YR_MNTH
The value nextmonth creates the next month's rev_yr_mnth correctly however when I try to use this created value in the where clause it brings back nothing in the nextamount field.
It's like it does not recognize the created value as a true value. What do I need to do to have the where clause recognize the value?
Using CTE you can add condition on nextmonth.
With CTE As (
SELECT TOP (1000)
[DEMAND_POINT_ID],
[DPM_XREF_ID],
[UTIL_TYPE],
[ACCOUNT_ID],
[REV_YR_MNTH],
[TOTAL_AMOUNT],
(SELECT CAST(LEFT((SELECT CONVERT(varchar, DATEADD(month, 1, LEFT(REV_YR_MNTH, 4) + '-' + RIGHT(REV_YR_MNTH, 2) + '-' + '01'), 112)), 6) AS int)) AS nextmonth,
(SELECT de2.[TOTAL_AMOUNT]
FROM [DEQEnergyUsage].[dbo].[DST_ENERGY_USAGE_AGGR] de2
WHERE de2.ACCOUNT_ID = de.ACCOUNT_ID
AND de2.REV_YR_MNTH = (SELECT CAST(LEFT((SELECT CONVERT(varchar, DATEADD(month, 1, LEFT(REV_YR_MNTH, 4) + '-' + RIGHT(REV_YR_MNTH, 2) + '-' + '01'), 112)), 6) AS int))) AS nextamount
FROM
[DEQEnergyUsage].[dbo].[DST_ENERGY_USAGE_AGGR] de
WHERE
ACCOUNT_ID =1
ORDER BY
ACCOUNT_ID, de.REV_YR_MNTH
)
select * from CTE
-- Where nextmonth condition

Calculate and Display Total Experience Months in YY/MM format in Sql Server

Consider the following code.
create table #temp (Min_Expr_InMonths int, Max_Expr_InMonths int)
insert into #temp values (40, 98)
insert into #temp values (null, null)
insert into #temp values (0, 0)
insert into #temp values (133, 145)
select ' (Exp - ' +
Convert(varchar, Case when j.Min_Expr_InMonths/12 < 10 then '0' + convert(varchar, j.Min_Expr_InMonths/12) else j.Min_Expr_InMonths/12 end) + '/' +
Convert(varchar,
case when j.Min_Expr_InMonths - ((j.Min_Expr_InMonths/12)*12) < 10 then '0' + convert(varchar, j.Min_Expr_InMonths - ((j.Min_Expr_InMonths/12)*12)) else
j.Min_Expr_InMonths - ((j.Min_Expr_InMonths/12)*12) end) + ' to ' + Convert(varchar,
Case when j.Max_Expr_InMonths/12 < 10 then '0' + convert(varchar, j.Max_Expr_InMonths/12) else j.Max_Expr_InMonths/12 end) + '/' +
Convert(varchar,
case when j.Max_Expr_InMonths - ((j.Max_Expr_InMonths/12)*12) < 10 then '0' + convert(varchar, j.Max_Expr_InMonths - ((j.Max_Expr_InMonths/12)*12)) else
j.Max_Expr_InMonths - ((j.Max_Expr_InMonths/12)*12) end) + ')' from #temp j
Output of the above query is as follows.
YY/MM
(Exp - 3/4 to 8/2)
NULL
(Exp - 0/0 to 0/0)
(Exp - 11/1 to 12/1)
What I wanted to achieve is as follows.
YY/MM
(Exp - 03/04 to 08/02)
(Exp - 00/00 to 00/00)
(Exp - 00/00 to 00/00)
(Exp - 11/01 to 12/01)
Is there a simpler way to achieve this, my query looks very untidy and difficult to read, also I am not sure about the performance as the DB rows increase.
Please Try below simplest query:
select 'Exp - ' +
right('00' + convert(varchar(2),coalesce(Min_Expr_InMonths,0)/12),2) + '/' +
right('00' + convert(varchar(2),coalesce(Min_Expr_InMonths,0)%12),2) + ' to '+
right('00' + convert(varchar(2),coalesce(Max_Expr_InMonths,0)/12),2) + '/' +
right('00' + convert(varchar(2),coalesce(Max_Expr_InMonths,0)%12),2) as 'YY/MM'
from #temp
Corrected select query:
SELECT '(Exp - ' +
CASE
WHEN j.Min_Expr_InMonths IS NULL
THEN '00'
WHEN (j.Min_Expr_InMonths/12 >= 10)
THEN CONVERT(VARCHAR, j.Min_Expr_InMonths/12)
ELSE
CONCAT('0',CONVERT(VARCHAR, j.Min_Expr_InMonths/12))
END
+ '/' +
CASE
WHEN j.Min_Expr_InMonths IS NULL
THEN '00'
WHEN j.Min_Expr_InMonths - ((j.Min_Expr_InMonths/12)*12) >= 10
THEN CONVERT(VARCHAR,j.Min_Expr_InMonths - ((j.Min_Expr_InMonths/12)*12))
ELSE
CONCAT('0',CONVERT(VARCHAR, j.Min_Expr_InMonths - ((j.Min_Expr_InMonths/12)*12)))
END
+ ' to ' +
CASE
WHEN j.Max_Expr_InMonths IS NULL
THEN '00'
WHEN j.Max_Expr_InMonths/12 >= 10
THEN CONVERT(VARCHAR, j.Max_Expr_InMonths/12)
ELSE
CONCAT('0',j.Max_Expr_InMonths/12)
END
+ '/' +
CASE
WHEN j.Max_Expr_InMonths IS NULL
THEN '00'
WHEN j.Max_Expr_InMonths - ((j.Max_Expr_InMonths/12)*12) >= 10
THEN CONVERT(VARCHAR, j.Max_Expr_InMonths - ((j.Max_Expr_InMonths/12)*12))
ELSE
CONCAT('0',CONVERT(VARCHAR,j.Max_Expr_InMonths - ((j.Max_Expr_InMonths/12)*12)))
END
+ ')'
FROM #temp j
OUTPUT
(Exp - 03/04 to 08/02)
(Exp - 00/00 to 00/00)
(Exp - 00/00 to 00/00)
(Exp - 11/01 to 12/01)
For Demo Follow the link:
http://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=d462f3f8cc4b945e01a7d594b016a105

SQL convert data type

I have two column with "text" datatype, i need to convert the the entire data in the first column to "datetime" data type, and the second column to "decimal(10,3)" data type.
Example of the current data:
first column: 20090901000005 covert to 2009/08/01 00:00:05
second column: .125 convert to 00.125
Any one can help Please :)
You can use something like this:
select cast(cast(col1 as varchar(8)) as datetime) +
cast(left(right(cast(col1 as varchar(14)), 6), 2) + ':' +
substring(right(cast(col1 as varchar(14)), 6), 2, 2) + ':' +
right(right(cast(col1 as varchar(14)), 6), 2) as datetime) newDate,
cast(cast(col2 as varchar(10)) as decimal(10, 3)) newDecimal
from yourtable
See SQL Fiddle with Demo
I would do it as follows:
SELECT
CONVERT(DATETIME,
(SUBSTRING(dateValue, 1, 8) + ' ' +
SUBSTRING(dateValue, 9, 2) + ':' +
SUBSTRING(dateValue, 11, 2) + ':' +
SUBSTRING(dateValue, 13, 2))) as 'dateValue',
CONVERT(DECIMAL(10, 3), decimalValue) as 'decimalValue'
FROM text_table
You can use left and right to split string into parts. Then use convert function to convert it to date. ODBC canonical (120) format is: yyyy-mm-dd hh:mi:ss
CONVERT(datetime,
left( firstcol, 4 ) + '-' +
left( right( firstcol, 10 ) ,2 ) + '-' +
left( right( firstcol, 8 ) ,2 ) + ' ' +
left( right( firstcol, 6 ) ,2 ) + ':' +
left( right( firstcol, 4 ) ,2 ) + ':' +
right( firstcol, 2 )
, 120)
For second column:
CONVERT( float, right( secondcol, 3 ) ) / 1000

Retrieve duration query

I have a MS SQL 2005 server. I have a database by name STAT & 2 columns by name STARTRUN & ENDRUN and have many rows in it.
STARTRUN ENDRUN
20110910200007 20110910200017
20110910200028 20110910200037
20110910200048 20110910200057
It shows the start time and end time of an activity and is in YYYYMMDDHHMMSS format. The datatype for this column is VARCHAR. I am trying to write a SQL script where i can retrieve the duration of each activity and dump it to a csv file as shown below.
START DATE START TIME END DATE END TIME DURATION
10-09-2011 8:00:07 PM 11-09-2011 1:10:10 AM 5:10:03
Please help me.
First you'd have to find a way to convert your format to a datetime. The subquery below does that by making it look like an ODBC canonical date and then calling convert. Then you can combine more convert with datediff to get your desired output format.
select convert(varchar, startrun, 105) + ' ' +
substring(convert(varchar, startrun, 109), 13, 8) + ' ' +
substring(convert(varchar, startrun, 109), 25, 2)
, convert(varchar, endrun, 105) + ' ' +
substring(convert(varchar, endrun, 109), 13, 8) + ' ' +
substring(convert(varchar, endrun, 109), 25, 2)
, substring('0' + cast(datediff(hh, startrun, endrun)
as varchar), 1, 2) + ':' +
substring('0' + cast(datediff(mi, startrun, endrun) % 60
as varchar), 1, 2) + ':' +
substring('0' + cast(datediff(s, startrun, endrun) % 60*60
as varchar), 1, 2)
from (
select convert(datetime,
substring(startrun,1,4) + '-' +
substring(startrun,5,2) + '-' +
substring(startrun,7,2) + ' ' +
substring(startrun,9,2) + ':' +
substring(startrun,11,2) + ':' +
substring(startrun,13,2),
120) as startrun
, convert(datetime,
substring(endrun,1,4) + '-' +
substring(endrun,5,2) + '-' +
substring(endrun,7,2) + ' ' +
substring(endrun,9,2) + ':' +
substring(endrun,11,2) + ':' +
substring(endrun,13,2),
120) as endrun
from #YourTable
) as SubQueryAlias
Here's a working example at SE Data. See this question for exporting the result of a query to a CSV file.

How can I find out which data won't cast?

I have a SQL table with a date field defined as char(8), or 20090609, and a time field defined as char(4), or 1230. I am moving this data into another table and I want to combine the two fields and put them in a smalldatetime field in the new table. My query is like this:
INSERT NewTable(eventdate)
SELECT
CAST((datecol + ' ' + substring(timecol, 1, 2) + ':' + substring(timecol, 3, 2)) as smalldatetime)
FROM OldTable
When I run this, I get an error:
The conversion of char data type to
smalldatetime data type resulted in an
out-of-range smalldatetime value.
I've tried checking len(datecol) and len(timecol) to make sure that they are at least the correct number of characters. I have no idea how I can find the offending data, any suggestions? The database is SQL2000 and I'm using SMO 2008.
Try this:
SELECT datecol, timecol
FROM OldTable
WHERE ISDATE(datecol + ' ' + substring(timecol, 1, 2) + ':' + substring(timecol, 2, 2)) = 0
That will show you which rows cannot be converted successfully.
It is probably out of the range of acceptable smalldatetime values
January 1, 1900, through June 6, 2079
EDIT On closer inspection I think the substring parameters for the second portion of the time may be incorrect (which may be the whole problem) updated below to reflect substring(timecol, 3, 2)
New Approach this sql does assume that all dates are 8 characters in length, and all times are 4.
Select SubString(DateCol, 1, 4) as tehYear,
Substring(DateCol, 5,2) as tehMonth,
SubString(DateCol, 7,2) as tehDay,
SubString(TimeCol, 1,2) as tehHour,
Substring(TimeCOl, 3,4) as tehMinute,
*
from OldTable
where
(SubString(DateCol, 1,4) > 9999 or SubString(DateCol, 1,4) < 1753)
OR (Substring(DateCol, 5,2) > 12 or Substring(DateCol, 5,2) < 1)
OR (SubString(DateCol, 7,2) > 31 or SubString(DateCol, 7,2) < 1)
OR (SubString(TimeCol, 1,2) > 23 or(SubString(TimeCol, 1,2) < 0)
OR (Substring(TimeCOl, 3,4) > 59 or Substring(TimeCOl, 3,4) <0)
Try casting to datetime and seeing if there are any dates that fall outside of that range to identify your problem data.
SELECT
CAST((datecol + ' ' + substring(timecol, 1, 2) + ':' + substring(timecol, 3, 2))
as datetime)
FROM OldTable
Where CAST((datecol + ' ' + substring(timecol, 1, 2)
+ ':' + substring(timecol, 3, 2)) as datetime)
> Cast('06/06/2079' as datetime) or CAST((datecol + ' '
+ substring(timecol, 1, 2) + ':' + substring(timecol, 3, 2)) as datetime)
< Cast('01/01/1900' as datetime)
If you run the query in query analyzer it should tell you what row the error occured!