SQL Server: convert and merge separate date and time columns (both integers) - sql

I am working on a query, where I have to fill a table's column ([Result_DateTime]) with datetime values.
The datetime based on two columns, both integer. One contains the date and the other is the time, as it is.
As you can see from the picture, it is a bit difficult to merge and convert these values to an actual datetime, because of the way they are stored. Mainly the time value causing problems.
I concluded how to convert the date column:
CONVERT(DATETIME, LEFT(20200131, 8))
but then I got stuck - what to do with the time and how to merge the two into one datetime effectively?
Using function STUFF looks nasty...
Could you help me out please? I am using SQL Server 2014

Below is one method to do it:
SELECT CAST(Convert(DATE, LEFT(DATEUPDT, 8)) AS VARCHAR(10)) +' '+CAST (TIMEUPDT/100 AS VARCHAR(4)) + ':' + CAST(TIMEUPDT%(100 * (TIMEUPDT/100)) AS VARCHAR(10))+':00'
FROM TEST_TABLE_TIME;

I think I found one solution. What I tried is to avoid using varchar conversions because of how the time column's zeros are cut off. However, I am not convinced that this is the most effective way to do so:
DECLARE #DateInt int = 20200131
DECLARE #TimeInt int = 345 -- 03:45:00
SELECT CONVERT(DATETIME, LEFT(#DateInt, 8)) +
CAST(DATEADD(second, FLOOR(#TimeInt / 100) * 3600 + FLOOR(#TimeInt / 1) % 100 * 60, 0) as datetime)
I was testing it with various time values, it is working.

Related

SQL Creating a table for song duration

I am trying to create a table in SQL which is about Music, it should contain songDuration. Which means I gotta hold minutes:seconds information in the table. But i have no idea what to use for the type. I am using SQL server.
Edit: I want to use the database for an ASP.NET Core web application. I was using a ready-to-use SQL database like northwnd. Now, I am trying to create one. So, I will not see the timing with SELECT function in SQL query. So, I need to use something that makes it mm:ss otomaticly. Is there is a type that I can decleare like that?
create table musics(
songDuration type,
...)
Why just don't you use int?
So you could calculate duration in the way you like.
E.g. minutes,hours, etc.
There's a datatype time which would be the logical choice, that stores it in format HH:mm:ss with an optional amount of fractional seconds determined by the size you declare the field (e.g. time(3) holds it to three decimal places)
If your source data is already in this notation it makes it getting it in the table easy and simple sorting/filtering operates as you expect. The downside to doing this is if you want to do certain operations such as SUM or AVG (because as a_horse_with_no_name pointed out in their comment) time technically represents a point in time not a duration and you'd have to do some workaround like so:
SELECT totalduration = SUM(DATEDIFF(SECOND, '0:00:00', duration))
FROM dbo.table
Alternatively you could store the number of (say) seconds in the duration using an int, but if you don't already have the information in that format you'd have to do some (light) conversion when inserting the data, and then back if you want to display in mm:ss
e.g:
SELECT CONVERT(varchar, DATEADD(SECOND, durationinseconds, 0), 8) FROM dbo.table
which would convert it back to hh:mm:ss format.
I do this by using an int column, and store the seconds there.
In your client you can calculate from the seconds howmany days, hours, minutes and seconds it is and display it like you want.
To display it in sql you can use this for example
declare #seconds int = 350
select right('00' + convert(varchar, datepart(hour, dateadd(s, #seconds, 0)) + ((#seconds / 86400) * 24)), 2)
+ ':' + right('00' + convert(varchar, datepart(minute, dateadd(s, #seconds, 0))), 2)
+ ':' + right('00' + convert(varchar, datepart(second, dateadd(s, #seconds, 0))), 2)
this will display
00:05:50
which is 0 hours, 5 minutes and 50 seconds
IF the value of seconds is larger than a day, this will be no problem. The number of hours will simply be greater
a value of 350000 will display 97:13:20

SQL Server Converting Decimal into Time hh:mm, I need the total hours

I need to be able to get the total hours and minutes if it is over 24 hours from a decimal column in SQL Server.
This is the code I am using:
CAST(CAST(DATEADD(SECOND, 1654.86 * 60, 0) AS Time(0)) AS VARCHAR(5))
Since it's over 24 hours the output is "03:34" I would like for it to be "27:34" or if possible to tell me it will take 3 working days and "03:34" (not sure how that would work).
Thank you in advance! Paul
As explained in the comments, the time data type is not designed to represent any sort of interval or timespan, it is only designed to represent clock time. As such, it is not capable of displaying 27 hours. Instead you need to build this string yourself with methods other than simple CAST as type:
DECLARE #d table(decimal_column decimal(15,2));
INSERT #d(decimal_column) VALUES(1654.86);
SELECT d.decimal_column,
nice_time = CONVERT(varchar(11), FLOOR(h)) + ':'
+ RIGHT('0' + CONVERT(varchar(11), FLOOR(m)), 2)
FROM #d AS d
CROSS APPLY
(
VALUES(d.decimal_column/60, d.decimal_column%60)
) AS extracted(h,m);
Results:
decimal_column
nice_time
1654.86
27:34
Example db<>fiddle
You may have edge cases where you want actual rounding logic instead of FLOOR() - but if you have those cases, include them in your question so we know the desired output.
select CONVERT(VARCHAR, CONVERT(INT, 1654.86/60)) + ':'
+ CONVERT(VARCHAR, CONVERT(INT, 1654.86-(CONVERT(INT, 1654.86/60)*60)))
You can create a function for this query, it is very performance. Because we will not use the same operations in multi sections.

How to properly combine static hour and minute

We have in our table, in SQL Server 2008, the datetime is only holding the date.
There is also an hour col and a minute col, there are for the appointment. the are both columns defined as number.
The hour is typically like this:
12.00
and minute is like 40.00. I tried adding them but it gives a total rather than
12:40 which is what we need. How can I get this to show 12:40. With the : would be better.
Well... taking a shot here, for SQL Server
declare #table table (d datetime,h decimal(4,2), m decimal(4,2))
insert into #table
values
('20170113',12.00,40.00),
('20170113',9.00,8.00)
select
d + cast(left(h,len(floor(h))) + ':' + cast(left(m,len(floor(m))) as varchar(2)) + ':' + '00' as datetime)
from
#table
Prepend 00. to minutes - please note that dot there.
Convert both to times.
Add them.
Convert result back to string.
This way You will also corectly handle situation like 12.40 + 00.30.00 = 13.10

Convert Number to Date in SQL Server with Exception in Month-End

I have an INT column in my table. This column stores the date in special format. I'm trying to convert that column to DATE type.
For example, we keep '2016-03-14' as 20160314.
The exception is, for the last of each month, we do not store day.
So for '2016-03-31' we store 201603 and I have to consider if the number is less than 999999 or not to find is the number represents a month-end or other days in month.
So far, I have 2 queries to achieve this task:
Query 1:
This is all mathematics formula.
declare #k int = 20160321
--declare #k int = 201603
select
IIF(#k < 999999
, EOMONTH(DATEFROMPARTS(#k /100, #k % 100, 1), 0)
, DATEFROMPARTS(#k /10000, (#k / 100) % 100, #k % 100)
)
Query 2:
This one is using string manipulation.
declare #k int = 20160321
--declare #k int = 201603
select
IIF(#k < 999999
, EOMONTH(cast(LEFT(#k, 4) + '-' + RIGHT(#k, 2) + '-01' as date), 0)
, cast(LEFT(#k, 4) + '-' + RIGHT(LEFT(#k, 6), 2) + '-' + RIGHT(#k, 2) as date )
) AS DateColumn
I need to do the conversion formulas in WHERE clause. Something like:
SELECT K, Dt, Name -- and more fields
FROM tbl
WHERE IIF(K < 999999
, EOMONTH(DATEFROMPARTS(K /100, K % 100, 1), 0)
, DATEFROMPARTS(K /10000, (K / 100) % 100, K % 100)
) < GetDate()
And performance is important
Question: Is there a better way to do this? Possibly a ways that SQL Server can use the clustered index I have on K column.
I would expect that Query 1 would perform better, but you'd have to test it to be sure. I have no idea what kind of performance datefromparts() and datetimefromparts() have. They're relatively new, so it wouldn't shock me if they were magically terrible for no good reason. You're comparing performance of string manipulation and type casting vs the performance of arithmetic and type casting. My guess is it's mostly a wash, but that arithmetic is probably faster.
The options that strike me for a solution performance-wise are: a) Add a datetime column to your table. b) Add a computed column to the table. If you make a PERSISTED column, you could even create an index on it. c) Create a view (an indexed view if you can jump through the requirement hoops). d) Create a new table with the datetime field and update it.
Both (a) and (d) duplicate data, so they're not as great of solutions as they first appear.
I always have found computed columns to be a little gross, but they work well enough. If you create a view, you'll have to INNER JOIN it back to use it, but in most systems JOINS are very fast.
I'd probably look at creating a persisted computed column or a view. The best solution, of course, is to not store dates as integers in the first place.
You might try this query:
SELECT CASE
WHEN #K < 999999 THEN EOMONTH(TRY_CONVERT(date, CAST(#K * 100 + 1 AS VARCHAR(10))))
ELSE TRY_CONVERT(date, CAST(#K AS VARCHAR(10)))
END AS K_Date
The reason this might work is that YYYYMMDD is one of the ISO date formats. I'd try TRY_CONVERT() before CONVERT() because the query engine can decide to evaluate all the CONVERT without looking at the CASE conditional and throw errors.

How to Handle DATEDIFF(MINUTE, '00:00', '24:20') Like scenario?

There is a column in my Table. In which we are storing string value in format 'HH:MM'.During fetching records with this table every things works ok with
DATEDIFF(MINUTE, '00:00', ColumnName)
Problem is when we have Value greater than 23:59.
Its showing error like
Conversion failed when converting date and/or time from character string.
Can anybody suggest me the right approach for achieving this scenario.
If you are storing the value as something other than a time, why not just store the number of minutes and convert to whatever format you want on output?
Otherwise, I would suggest that you simply convert the value to minutes:
select (cast(left(ColumnName, 2) as int) * 60 +
cast(right(ColumnName, 2) as int)
) as Minutes
If you are not using date/time values, there is no requirement for using the functions specifically designed for them.
EDIT:
To handle hours longer than 99, use charindex():
select (cast(left(ColumnName, charindex(':', ColumnName) - 1) as int) * 60 +
cast(right(ColumnName, 2) as int)
) as Minutes
So it sounds like your saving the length of a time period. Try storing it in minutes. My query can handle numbers of different lengths since it's based on the colon.
DECLARE #yourTable TABLE (ColumnName VARCHAR(10));
INSERT INTO #yourTable
VALUES ('100:00'),
('24:20');
SELECT ColumnName,
(hr * 60) + minut AS time_period_in_minutes
FROM #yourTable
CROSS APPLY (SELECT CAST(SUBSTRING(ColumnName,0,CHARINDEX(':',ColumnName)) AS INT),
CAST(SUBSTRING(ColumnName,CHARINDEX(':',ColumnName) + 1,LEN(ColumnName)) AS INT)) CA(hr,minut)
Results:
ColumnName time_period_in_minutes
---------- ----------------------
100:00 6000
24:20 1460
Try to this
select DATEDIFF(MINUTE, '00:00', case when ISDATE(ColumnName)=0 then '00:00' else ColumnName end )