Convert time interval into decimal hours in SQL Server - sql

I have a time interval in the format '88:52:57'
I need to convert it into a decimal hours in the format 88.88
How can I do this?
I have the data initially loaded as a varchar

You can use left, right and substring to extract the values and then do some calculations.
declare #S varchar(8) = '88:52:57';
select left(#S, 2) + substring(#S, 4, 2)/60.0 + right(#S, 2)/60.0/60.0;
If you not always have two digit values you can use parsename to get the values instead.
declare #S varchar(20) = '088:052:057';
select parsename(S.X, 3) + parsename(S.X, 2)/60.0 + parsename(S.X, 1)/60.0/60.0
from (select replace(#S, ':', '.')) as S(X)

Try it like this (best create an UDF from this):
First I split the Time-Variable on its double dots via XML. The rest is simple calculation...
DECLARE #YourTime VARCHAR(100)='88:52:57';
WITH Splitted AS
(
SELECT CAST('<x>' + REPLACE(#YourTime,':','</x><x>') + '</x>' AS XML) TimeParts
)
,TimeFract AS
(
SELECT TimeParts.value('/x[1]','float') AS HourPart
,CAST(TimeParts.value('/x[2]','int') * 60 + TimeParts.value('/x[3]','int') AS FLOAT) Seconds
FROM Splitted
)
SELECT HourPart + Seconds/3600
FROM TimeFract
The result
88,8825

Try this, solution is based on conversions, making it safe, if the format is always (h)h:mi:ss:
DECLARE #S varchar(8) = '88:52:57';
SELECT
CAST(REPLACE(left(#S, 2), ':', '') as int)+
CAST(CAST(CAST('0:'+RIGHT(#S, 5) as datetime) as decimal(10,10)) * 24 as decimal(2,2))
Result:
88.88

Related

How to extract string from a text in SQL Server

I have texts like "DBName_TemplateDB_TESTDB01234_document" and "DBName_TemplateDB_TESTDB01234678_document". From both texts need to extract string between second underscore() and last underscore() like "TESTDB01234" and "TESTDB01234678".
Can you please help how to string in SQL Server using SUBSTRING and CHARINDEX?
Example:
Input Text: 'DBName_TemplateDB_TESTDB01234_document'
Output: TESTDB01234
Input Text: 'DBName_TemplateDB_TESTDB01234678_document'
Output: TESTDB01234678
I tried to extract and it's working only from the first underscore like below.
declare #Dbname varchar(max) = '#new#-TESTDB01234_document'
select substring( LEFT(#DbName,charindex('_',#DbName)-1),charindex('TEST',#DbName),len(LEFT(#DbName,charindex('_',#DbName)))-1)
Will this work for you?
--OPTION ONE: SUBSTRING
DECLARE #Start INT = CHARINDEX('TEST', #Dbname);
DECLARE #End INT = LEN(#Dbname) - (CHARINDEX('_', REVERSE(#Dbname)) - 1) - #Start;
SELECT SUBSTRING(#Dbname, #Start, #End) AS [Name]
--OPTION TWO: DOUBLE REPLACE
SELECT REPLACE(REPLACE(#Dbname, 'DBName_TemplateDB_', ''), '_document', ''); AS [Name]
--OPTION THREE: STRING_SPLIT
SELECT TOP 1 value AS [Name]
FROM STRING_SPLIT(#Dbname, '_')
WHERE value LIKE 'Test%'
I added a few options, sorry if its outside the scope of the question.
Using charindex
declare #Dbname varchar(max) = 'DBName_TemplateDB_TESTDB01234678_document'
select right(left(#DbName,third - 1), third - second - 1)
from (
select charindex('_',#DbName,charindex('_',#DbName) + 1) second,
charindex('_',#DbName,charindex('_',#DbName,charindex('_',#DbName) + 1) + 1) third
) t
If you are looking for data between the second and the last underscore, I will give the following approach as there might be more underscores between these ones:
declare #Dbname varchar(max) = 'DBName_TemplateDB_TESTDB01234678_1_2_3_document'
DECLARE #DbnameXML XML = '<a>' + REPLACE(#Dbname, '_', '</a><a>') + '</a>';
SELECT STRING_AGG([value], '_') WITHIN GROUP (ORDER BY [value_id])
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY T.c) - 1
,T.c.value('.', 'VARCHAR(128)')
,COUNT(1) OVER()
FROM #DbnameXML.nodes('a') T(c)
) DS ([value_id], [value], [values_count])
WHERE [value_id] > 1
AND [value_id] + 1 < [values_count]

SQL Server : substring from specific position of '-' hyphen

I need to perform a substring operation in SQL Server and get a string from start of hyphen character (-).
My input string is :
'44345434595-E535-12349-5273-202003-16785'
and I want to extract the string from 4th instance of hyphen to 5th instance of hyphen and my desired result is : 202003
You can use string_split function in sqlserver
declare #str varchar(max)= '44345434595-E535-12349-5273-202003-16785'
select * from (select value, row_number() over (order by charindex('-' + value + '-', '-' + #str + '-')) rn
from string_split(#str, '-')) t1
where t1.rn in (5)
Since there's no guarantee of ordering using string_split function, we need to sort by position based on your -
row_number() over (order by charindex('-' + value + '-', '-' + #str + '-'))
If your input string has fixed format you can set position and lenght directly
SELECT SUBSTRING(yourColumn, 29, 5) FROM YourTable
If the Format is Fixed You can use Substring for that:
DECLARE #STR VARCHAR(100)
SELECT #STR='44345434595-E535-12349-5273-202003-16785'
SELECT SUBSTRING(#STR, 29, 6)
Output: 202003
Below is the code that might suit your requirement and will work if the input has exactly 5 hypen.
DECLARE #data varchar(50)= '44345434595-E535-12349-5273-202003-16785'
select
reverse(
SUBSTRING
(
SUBSTRING
(
reverse(#data),
charindex('-',reverse(#data),1)+1,
len(#data)
),
1,
charindex('-',SUBSTRING(reverse(#data),
charindex('-',reverse(#data),1)+1,
len(#data)))-1)
);

Calculate total Working hours from sql column

Expected result is 3201:20. I have done this with split with ":". Please suggested best way to achieve this.
DECLARE #tmpTime TABLE
(
RowId INT IDENTITY(1, 1),
EmployeeId INT,
TotalWorkingTime NVARCHAR(10)
);
INSERT INTO #tmpTime
(
EmployeeId, TotalWorkingTime
)
VALUES
(1,N'1500:30'),
(2,N'1700:50');
SELECT SUM(TotalWorkingTime) FROM #tmpTime
SQL Server doesn't off a time type with more than 24 hours. So, don't think of what you are doing in terms of time. It is just a funky string representation of numbers.
So, you can parse the value into numbers, do the summation, and then reconstruct the value:
select (cast(sum(hh) + sum(mm) / 60 as varchar(255)) + ':' +
right('00' + cast(sum(mm) % 60 as varchar(255)), 2)
) as hhmm
from ( VALUES (1,N'1500:30'), (2,N'1700:50') ) t(EmployeeId, TotalWorkingTime) cross apply
(values (cast(left(TotalWorkingTime, charindex(':', TotalWorkingTime) - 1) as int),
cast(stuff(TotalWorkingTime, 1, charindex(':', TotalWorkingTime), '') as int)
)
) v(hh, mm)
As you can see from #GordonLinoff's answer, your query is quite complex when using a VARCHAR to represent what is really a duration of time. If you represent your data in a more natural way, your query becomes much simpler. For example, if you store your time worked as an integer (total minutes), you can use an intermediate CTE and a couple of CROSS APPLYs to get what you need:
-- note that TotalWorkingTime is now TotalWorkingTimeMinutes
DECLARE #tmpTime TABLE
(
RowID INT IDENTITY(1,1),
EmployeeID INT,
TotalWorkingTimeMinutes INT
);
-- while I'm using a calculation to show
-- how the minutes get added, this would likely
-- be done by the application, before it gets
-- sent to the database.
INSERT INTO #tmpTime
(EmployeeID, TotalWorkingTimeMinutes)
VALUES
(1, (1500 * 60) + 30),
(2, (1700 * 60) + 50);
-- I think this intermediate CTE makes things a bit clearer.
-- but of course, you can inline it as well.
WITH SummedMinutesWorked(SummedMinutes) AS
(
SELECT SUM(TotalWorkingTimeMinutes)
FROM #tmpTime
)
-- you can use the CROSS APPLY to get the hours,
-- then reference those to get the "remainder minutes"
-- the SELECT has to cast your hours and minutes to a VARCHAR
-- for concatenation
SELECT CAST(H AS VARCHAR(255)) + ':' + CAST(M AS VARCHAR(255))
FROM SummedMinutesWorked
CROSS APPLY (SELECT SummedMinutes / 60 AS H) AS HoursWorked
CROSS APPLY (SELECT SummedMinutes - (H * 60) AS M) AS RemainderMinutes
You can try using left() and right() function for finding character before and afer ':'
select
concat
(
sum(cast(left(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-1) as int)),
':',
case when sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int))>60 then sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int))-60 else sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int)) end
) FROM #tmpTime

Formatting a number as a monetary value including separators

I need some help with a sql transformation. This part of query that I have been provided with:
'$' + replace(cast((CAST(p.Price1 AS decimal(10,2)) * cast(isnull(p.Multiplier,1) as decimal(10,2))) as varchar), '.0000', '')
Basically, it ends up being a varchar that looks like this: $26980
I need to insert a comma at the thousand and million mark (if applicable). So in this instance, $26,980
What's the easiest way to do that without having to rewrite the whole thing?
Do it on the client side. Having said that, this example should show you the way.
with p(price1, multiplier) as (select 1234.5, 10)
select '$' + replace(cast((CAST(p.Price1 AS decimal(10,2)) * cast(isnull(p.Multiplier,1) as decimal(10,2))) as varchar), '.0000', ''),
'$' + parsename(convert(varchar,cast(p.price1*isnull(p.Multiplier,1) as money),1),2)
from p
The key is in the last expression
'$' + parsename(convert(varchar,cast(p.price1*isnull(p.Multiplier,1) as money),1),2)
Note: if p.price1 is of a higher precision than decimal(10,2), then you may have to cast it in the expression as well to produce a faithful translation since the original CAST(p.Priced1 as decimal(10,2)) will be performing rounding.
If you really must do it in TSQL you can use CONVERT(), but this sort of thing really doesn't belong in the database:
declare #m money = 12345678
-- with decimal places
select '$' + convert(varchar, #m, 1)
-- without decimal places
select '$' + replace(convert(varchar, #m, 1), '.00', '')
You could turn this into a function, it only goes 50 characters back.
DECLARE #input VARCHAR(50)
SELECT #input = '123123123.00'
SELECT #input = CASE WHEN CHARINDEX('.', #input) > offset +1
THEN STUFF(#input, CHARINDEX('.', #input) - offset, 0, ',')
ELSE #input END
FROM (SELECT 3 offset UNION SELECT 7 UNION SELECT 12 UNION SELECT 18 UNION SELECT 25 UNION SELECT 33 UNION SELECT 42) b
PRINT #input
The offset grows by +1 for each position, because it's assuming you've already inserted the commas for the previous positions.

How to display the number “12” in the format of “0000012”

How to display the number “12” in the format of “0000012” Using SQL
if you just want the number 12 then
SELECT '0000012'
else if it is a number you need to display with 7 digits:
SELECT RIGHT('0000000'+CONVERT(nvarchar,FieldValue),7)
More info on the question would help.
How about something like
DECLARE #Val INT
DECLARE #Length INT
SELECT #Val = 12,
#Length = 7
SELECT REPLICATE('0',#Length - LEN(CAST(#Val AS VARCHAR(MAX)))) + CAST(#Val AS VARCHAR(MAX))
REPLICATE (Transact-SQL)
Repeats a string value a specified
number of times.
The shortest answer that probably also works best is just
SELECT RIGHT(10000000+ #Val, #Length)
e.g.
SELECT RIGHT(10000000+ NumColumn, 7)
I haven't got a server to test with, but you should be able to use the following in your SQL:
'RN ' + RIGHT(CAST(auto_id AS VarChar) + '000000', 6)
eg:
Code:
SELECT 'RN ' + RIGHT(CAST(auto_id AS VarChar) + '000000', 6)
FROM tablename
This is not efficient but will work for your case -
DECLARE #num int
DECLARE #totalChar int
SET #num = 12
SET #totalChar = 10
SELECT right('0000000000' + CONVERT(varchar, #num), #totalChar)
Output -
000000012
This should easily port to other SQLs:
SELECT
REVERSE(CAST(REVERSE(CAST(CAST(12 AS INTEGER) AS VARCHAR(7))) + '000000' AS CHAR(7)))
SELECT REPLACE(STR(12, 7), ' ', '0')