Snowflake converting numeric value into HHMMSS format - sql

I have a column that has number in it in the format of HHMMSS but the number is not consistent (not all have six digits), ex: "83455" "153651" "91251".
The number 83455 would mean 8:34 am and 55 as SS. I tried converting into varchar and use TO_TIME but the output is not the same as it is. Similarly, I also tried converting into timestamp then get the time from it but it just won't work. The output I want here would be 8:34:55, what is the best way to convert the number?

Try this. I split hours minutes and seconds and then concatenate them into time format.
SELECT
CAST(FLOOR(col / 10000) || ':' ||
FLOOR(MOD(col / 100, 100)) || ':' ||
MOD(col, 100) AS TIME) AS converted_time
FROM
yourtable
MOD()

An alternative approach is to use the built in function for this task.
TRY_TO_TIME().
Sometimes the built in functions are easier to read, understand, less typing, optimized (runs faster/cheaper).
SELECT
TRY_TO_TIME (DONT_WASTE, 'HH24MISS" )VOLIA
,TO_CHAR (VOLIA, 'HH12:MI:SS AM' ) AM_PM
FROM
(SELECT '83455 'DONT_WASTE UNION SELECT '153651 'UNION SELECT '91251')

The core of this problem is the format string was wrong
MM is Month, MI is minutes.
The first path I went down was slicing the string up, but the TO_TIME/TRY_TO_TIME both handle the smaller string of the pre lunchtime, but does not handle no hours, for that you might need to pad if you have such truncated values from number I assume:
select column1
,try_to_time(column1, 'HH24MMSS') as wrong
,try_to_time(column1, 'HH24MISS') as r1
,lpad(column1, 6, '0') as p
,try_to_time(p, 'HH24MISS') as r2
from values
('83455'),
('153651'),
('91251'),
('1251')
;
COLUMN1
WRONG
R1
P
R2
83455
null
08:34:55
083455
08:34:55
153651
null
15:36:51
153651
15:36:51
91251
09:00:51
09:12:51
091251
09:12:51
1251
12:00:01
null
001251
00:12:51
Thus inline it would be:
try_to_time(lpad(column1, 6, '0'), 'HH24MISS')

Related

Finding Average Time Length in SQL

I am a beginner in SQL and I am using Big Query. I am looking to find the average length of time.
My columns are in the image.
Can someone please tell me how to write a query to find the average time for the column ride_length in minutes? The ride_length column is in h:mm format.
You will need something like this:
SELECT AVG(
CAST( SPLIT( ride_length, ':' )[OFFSET(1)] AS NUMERIC )
+ CAST( SPLIT( ride_length, ':' )[OFFSET(0)] AS NUMERIC ) * 60
)
FROM TheTable
SPLIT is used to separate hours from minutes and then each result converted (CAST) to NUMBER.
[I did not test it]
Here is the data verification query (untested as well) to check on format consistency:
SELECT
ride_id,
ride_length
WHERE NOT REGEXP_CONTAINS(ride_length, r'^(\d+\:\d+)$)';

SQL Convert & Cast Nvarchar Time to a decimal

I'm working on a legacy database and need to parse info from one database to another, parsing it into the new database is easy enough but first I need to create the query to convert and cast the following in the legacy SQL Server database:
WorkedHours(NVARCHAR(10)) is in text format 07:30
I need to convert and cast this as a decimal ie 7.5
I have searched around for the answer to this but can not find anything that has worked, so thought I would put it out there to see if any of you has any ideas.
Edit - What I should of asked is. What is causing an error converting to an int from a character with a value of 0 when trying to trying to convert and cast a time to a decimal?
DATEDIFF(
MINUTE,
0,
CAST('07:30' AS TIME)
)
/
60.0
Works up to '23:59' only
EDIT:
Based on a comment elsewhere, you have some 'bad' values.
This may find them...
SELECT
*
FROM
yourTable
WHERE
TRY_CONVERT(TIME, worked_hours) IS NULL
And as such, this is a safer version of my expression....
DATEDIFF(
MINUTE,
0,
TRY_CONVERT(TIME, worked_hours)
)
/
60.0
(Returns NULL for values that failed to parse.)
There's no reason to pull out the date/time types. Just do some simple string parsing:
cast(left(right('0' + WorkedHours, 5), 2) as int)
+ cast(right(WorkedHours, 2) as int) / 60.00
This won't have any limitations on 24 hours or anything like that. It just assumes that you've got one or two digits before a colon and two digits after.
This should work in SQL Server and an example-string "1101:56" (1101h & 56 minutes) | in general from 0h to >24h:
-- Take all hours before ":" and all Minutes (2 digits) after ":" and convert it to decimal.
select convert(decimal,left('1101:56',CHARINDEX(':','1101:56')-1)) + ( convert(decimal,right('1101:56',2))/60 );
-- with column-placeholder "time_str_from_table"
select convert(decimal,left(time_str_from_table,CHARINDEX(':',time_str_from_table)-1)) + ( convert(decimal,right(time_str_from_table,2))/60 );
If the source table have NULL-Values, than use "ISNULL" with substitution-value "0.0":
-- with column-placeholder "time_str_from_table"
select isnull( ( convert(decimal,left(time_str_from_table,CHARINDEX(':',time_str_from_table)-1)) + ( convert(decimal,right(time_str_from_table,2))/60) ), 0.0);

Oracle - hh mm ss to hh:mm:ss with one exotic

I have an Oracel DB which contains two columns that have the format hhmmss. So 221000 stands for 22:10:00.
I want to make it to a right time format. The problem is that there is the value 240000, which is should be changed to 235959. Furthermore, leading zeros are omitted.
Does one know how to do this?
Greeting
You can try:
select replace(to_char(t, '00,00,00'), ',', ':')
This doesn't handle the 24:00:00, but that seems like a valid time. You can handle that using case:
select (case when t = 240000 then '23:59:59' -- I would use '00:00:00'
else replace(to_char(t, '00,00,00'), ',', ':')
end)
You could use a case expression to handle this usecase explicitly. For the others, you can convert this string to a date, and then format the date as you will:
SELECT CASE col
WHEN '240000' THEN '23:59:59'
ELSE TO_CHAR(TO_DATE(LPAD(col, 6, '0'), 'hh24miss'), 'hh24:mi:ss')
ENDi
FROM mytable
Assumptions:
Your table has a VARCHAR column holding the date in yyyymmdd
Your table has a VARCHAR or INT column holding a time in hh24miss
What you really ought to do:
ALTER TABLE ADD proper_date DATETIME;
UPDATE table SET proper_date = TO_DATE(datecol || LPAD(timecol, 6, '0'), 'yyyymmddhh24miss');
If your table has a datetime holding the date, and an int or varchar holding the time:
UPDATE table SET the_date = TO_DATE(TO_CHAR(datecol, 'yyyymmdd') || LPAD(timecol, 6, '0'), 'yyyymmddhh24miss');
Then drop the separated columns- always a terrible idea in the face of a datatype designed for holding these things
The simplest is probably to just convert the Hours separately from the minutes and seconds like so:
to_date(substr(t,-4),'miss') + to_number(substr(t,1,length(t)-4))/24
A key fact to note about this is that for hours >= 24 the resulting date will be a day or more later than those times with fewer hours, so subtracting the converted values 230000 from 240000 will result in a one hour difference as required.

How to perform arithmetic function in DATE TIME in SQL

I have four columns namely-
1. C_Date in YYYYMMDD format (varchar(255)) Eg. 20161231
2. C_Time in 4-digit Military format (varchar(255)) Eg. 2143
3. E_Date in YYYYMMDD format (varchar(255)) Eg. 20161230
4. E_Time in 4-digit Military format (varchar(255)) Eg. 1600
I want to Calculate the time between E event and C event. How can i perform this computation with a select statement?
Pretty simple to create a date type from the component values:
with data as (select '20161231' as c_date, '2143' as c_time)
select
convert(
datetime,
stuff(stuff(stuff(c_date + ' ' + c_time, 12, 0, ':'), 7, 0, '-'), 5, 0, '-'),
120
) as c_datetime
from data;
Use datediff() to calculate the time difference. You didn't specify how you wanted the output to look so I won't attempt a guess. There should be a hundred other questions out there with information relevant to your question though.
Also note that I did not append ':00' to the string to represent seconds. It seems to work though I couldn't track down an official document to confirm that. So to be safe you may want to tack that on as well. Arguably there could be a more universal format like ISO 8601 that would be a "better" solution. You get the idea though.
A small matter to convert your strings into a datetime. Then we use DateDiff() to calculate the differance between the two dates.
Declare #YourTable table (C_Date varchar(255),C_Time varchar(255),E_Date varchar(255),E_Time varchar(255))
Insert Into #YourTable values
('20161231','2143','20161230','1600')
;with cte as (
Select *
,CDT = try_convert(DateTime,C_Date+' '+stuff(C_Time,3,0,':'))
,EDT = try_convert(DateTime,E_Date+' '+stuff(E_Time,3,0,':'))
from #YourTable
)
Select CDT
,EDT
,Duration = concat(DateDiff(DD,EDT,CDT),' ',Format(DateAdd(Second,DateDiff(SECOND,EDT,CDT),'1899-12-31'),'HH:mm:ss'))
,AsSeconds = DateDiff(SECOND,EDT,CDT)
,AsMinutes = DateDiff(MINUTE,EDT,CDT)
From cte
Returns
CDT EDT Duration AsSeconds AsMinutes
2016-12-31 21:43:00 2016-12-30 16:00:00 1 05:43:00 106980 1783

Date arithmetic in SQL on DB2/ODBC

I'm building a query against a DB2 database, connecting through the IBM Client Access ODBC driver. I want to pull fields that are less than 6 days old, based on the field 'a.ofbkddt'... the problem is that this field is not a date field, but rather a DECIMAL field, formatted as YYYYMMDD.
I was able to break down the decimal field by wrapping it in a call to char(), then using substr() to pull the year, month and day fields. I then formatted this as a date, and called the days() function, which gives a number that I can perform arithmetic on.
Here's an example of the query:
select
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM-
concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
a.ofbkddt as mydate
from QS36F.ASDF a
This yields the following:
difference mydate
2402 20050402
2025 20060306
...
4 20110917
3 20110918
2 20110919
1 20110920
This is what I expect to see... however when I use the same logic in the where clause of my query:
select
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM-
concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
a.ofbkddt as mydate
from QS36F.ASDF a
where
(
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM
concat substr(char(a.ofbkddt),7,2) ) -- DD
) < 6
I don't get any results back from my query, even though it's clear that I am getting date differences of as little as 1 day (obviously less than the 6 days that I'm requesting in the where clause).
My first thought was that the return type of days() might not be an integer, causing the comparison to fail... according to the documentation for days() found at http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/db2/rbafzmst02.htm, it returns a bigint. I cast the difference to integer, just to be safe, but this had no effect.
You're going about this backwards. Rather than using a function on every single value in the table (so you can compare it to the date), you should pre-compute the difference in the date. It's costing you resources to run the function on every row - you'd save a lot if you could just do it against CURRENT_DATE (it'd maybe save you even more if you could do it in your application code, but I realize this might not be possible). Your dates are in a sortable format, after all.
The query looks like so:
SELECT ofbkddt as myDate
FROM QS36F.ASDF
WHERE myDate > ((int(substr(char(current_date - 6 days, ISO), 1, 4)) * 10000) +
(int(substr(char(current_date - 6 days, ISO), 6, 2)) * 100) +
(int(substr(char(current_date - 6 days, ISO), 9, 2))))
Which, when run against your sample datatable, yields the following:
myDate
=============
20110917
20110918
20110919
20110920
You might also want to look into creating a calendar table, and add these dates as one of the columns.
What if you try a common table expression?
WITH A AS
(
select
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM-
concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
a.ofbkddt as mydate
from QS36F.ASDF a
)
SELECT
*
FROM
a
WHERE
difference < 6
Does your data have some nulls in a.ofbkddt? Maybe this is causing some funny behaviour in how db2 is evaluating the less than operation.