incorrect date time format in Oracle DB, convert to hours and minutes - sql

Don't ask me why but for some reason we have a date time column that is in the wrong format that I need help converting.
Example timestamp from DB: 01-OCT-20 12.18.44.000000000 AM
In the example above the hours is actually 18 and the minutes is 44.
Not sure how this happened by 12 is the default for everything. All I want to do is get the difference in HH:MM from 2 timestamps, but i dont know how to convert this properly with the hours being in the minute section and the minutes being in the seconds section.
Example of what I'm looking for:
01-OCT-20 12.18.44.000000000 AM - 01-OCT-20 12.12.42.000000000 AM
Output: 06:02 . so the timespan would be 6 hours and 2 minutes in this case.
Thanks,

In the example above the hours is actually 18 and the minutes is 44.
Not sure how this happened by 12 is the default for everything. All I want to do is get the difference in HH:MM from 2 timestamps, but i dont know how to convert this properly with the hours being in the minute section and the minutes being in the seconds section.
To convert minutes to hours, you need to multiply by 60.
To convert seconds to minutes, you also need to multiply by 60.
So, if you want to convert the time part of the correct value then you take the time since midnight and multiply it all by 60.
If you want to get the difference between the current and correct time (after multiplying by 60) then you want to subtract the current time (which can be simplified to just multiplying by 59).
So to get the time difference you can use:
SELECT (value - TRUNC(value))*59 AS difference,
value + (value - TRUNC(value))*59 AS updated_value
FROM table_name;
So, for your sample data:
CREATE TABLE table_name ( value ) AS
SELECT TO_TIMESTAMP( '01-OCT-20 12.18.44.000000000 AM', 'DD-MON-RR HH12.MI.SS.FF9 AM' ) FROM DUAL
Then the output is:
DIFFERENCE | UPDATED_VALUE
:---------------------------- | :-------------------------
+000000000 18:25:16.000000000 | 2020-10-01 18:44:00.000000
db<>fiddle here
If you want to compare two wrong values just subtract one timestamp from the other and multiply by 60 (assuming that the hour will always be 12 AM or 00 in the 24 hour clock):
SELECT (value1 - value2) * 60 AS difference,
value1,
value1 + (value1 - TRUNC(value1))*59 AS updated_value1,
value2,
value2 + (value2 - TRUNC(value2))*59 AS updated_value2
FROM table_name;
So, for the sample data:
CREATE TABLE table_name ( value1, value2 ) AS
SELECT TO_TIMESTAMP( '01-OCT-20 12.18.44.000000000 AM', 'DD-MON-RR HH12.MI.SS.FF9 AM' ),
TO_TIMESTAMP( '01-OCT-20 12.12.42.000000000 AM', 'DD-MON-RR HH12.MI.SS.FF9 AM' )
FROM DUAL
The output is:
DIFFERENCE | VALUE1 | UPDATED_VALUE1 | VALUE2 | UPDATED_VALUE2
:---------------------------- | :------------------------- | :------------------------- | :------------------------- | :-------------------------
+000000000 06:02:00.000000000 | 2020-10-01 00:18:44.000000 | 2020-10-01 18:44:00.000000 | 2020-10-01 00:12:42.000000 | 2020-10-01 12:42:00.000000
Which gives the difference as 6 hours and 2 minutes.
db<>fiddle here

Related

How to bin timestamp data into buckets of custom width of n hours in vertica

I have a table which contains a column Start_Timestamp which has time stamp values like 2020-06-02 21:08:37. I would like to create new column which classifies these timestamps into bins of 6hours.
Eg.
Input :
Start_Timestamp
2020-06-02 21:08:37
2020-07-19 01:23:40
2021-11-13 12:08:37
Expected Output ( Here each bin is of 6hours width) :
Start_Timestamp
Bin
2020-06-02 21:08:37
18H - 24H
2020-07-19 01:23:40
00H - 06H
2021-11-13 12:08:37
12H - 18H
I have tried using TIMESERIES but can anyone help to generate output in following format
It's Vertica. Use the TIME_SLICE() function. Then, combine it with the TO_CHAR() function that Vertica shares with Oracle.
You can always add a CASE WHEN expression to change 00:00 to 24:00, but as that is not the standard, I wouldn't even bother.
WITH
indata(start_ts) AS (
SELECT TIMESTAMP '2020-06-02 21:08:37'
UNION ALL SELECT TIMESTAMP '2020-07-19 01:23:40'
UNION ALL SELECT TIMESTAMP '2021-11-13 12:08:37'
)
SELECT
TIME_SLICE(start_ts,6,'HOUR')
AS tm_slice
, TO_CHAR(TIME_SLICE(start_ts,6,'HOUR'),'HH24:MIH - ')
||TO_CHAR(TIME_SLICE(start_ts,6,'HOUR','END'),'HH24:MIH')
AS caption
, start_ts
FROM indata;
-- out tm_slice | caption | start_ts
-- out ---------------------+-----------------+---------------------
-- out 2020-06-02 18:00:00 | 18:00H - 00:00H | 2020-06-02 21:08:37
-- out 2020-07-19 00:00:00 | 00:00H - 06:00H | 2020-07-19 01:23:40
-- out 2021-11-13 12:00:00 | 12:00H - 18:00H | 2021-11-13 12:08:37
You can simply extract the hour and do some arithmetic:
select t.*,
floor(extract(hour from start_timestamp) / 6) * 6 as bin
from t;
Note: This characterizes the bin by the earliest hour. That seems more useful than a string representation, but you can construct a string if you really want.

Is 'YYYYQ' a valid DATETIME format for SQL? And if so, how do I make it with my data?

I have some tables in a postgres that have a column for year and a column for quarter (both stored as bigint). I need to be able to combine those together in the output of a query in the form of 'YYYYQ' (not the hard part) AND have the datatype of that field be datetime (<--the hard part).
The only query I have attempted that didn't fail was -
SELECT to_date((year::VARCHAR + quarter::VARCHAR),'YYYYQ') AS Stuff
FROM company.products
And while the output is in DATETIME format, there is no Quarter info in it.
Sample -
stuff
2011-01-01
2011-01-01
2012-01-01
2012-01-01
2012-01-01
Is it even possible to create output that has the format 'YYYYQ' AND is in DATETIME format? And if so, how?
From the PostgreSQL docs (emphasis mine):
In to_timestamp and to_date, weekday names or numbers (DAY, D, and related field types) are accepted but are ignored for purposes of computing the result. The same is true for quarter (Q) fields.
You can save the date of the 1st day of the quarter. Multiply the recorded quarter -1 by 3.
SELECT to_date('2021','YYYY') + interval '6 month';
?column?
---------------------
2021-07-01 00:00:00
SELECT to_char(to_date('2021','YYYY') + interval '6 month','YYYYQ');
to_char
---------
20213
SELECT q,
to_char(to_date('2021','YYYY') + interval '3 month'*(q-1),'YYYYQ') as YYYYQ,
to_date('2021','YYYY') + interval '3 month'*(q-1) as d
FROM generate_series(1,4) f(q);
q | yyyyq | d
---+-------+---------------------
1 | 20211 | 2021-01-01 00:00:00
2 | 20212 | 2021-04-01 00:00:00
3 | 20213 | 2021-07-01 00:00:00
4 | 20214 | 2021-10-01 00:00:00

Extract 30 minutes from timestamp and group it by 30 mins time interval -PGSQL

In PostgreSQL I am extracting hour from the timestamp using below query.
select count(*) as logged_users, EXTRACT(hour from login_time::timestamp) as Hour
from loginhistory
where login_time::date = '2021-04-21'
group by Hour order by Hour;
And the output is as follows
logged_users | hour
--------------+------
27 | 7
82 | 8
229 | 9
1620 | 10
1264 | 11
1990 | 12
1027 | 13
1273 | 14
1794 | 15
1733 | 16
878 | 17
126 | 18
21 | 19
5 | 20
3 | 21
1 | 22
I want the same output for same SQL for 30 mins. Please suggest
SELECT to_timestamp((extract(epoch FROM login_time::timestamp)::bigint / 1800) * 1800)::timestamp AS interval_30_min
, count(*) AS logged_users
FROM loginhistory
WHERE login_time::date = '2021-04-21' -- inefficient!
GROUP BY 1
ORDER BY 1;
Extracting the epoch gets the number of seconds since the epoch. Integer division truncates. Multiplying back effectively rounds down, achieving the same as date_trunc() for arbitrary time intervals.
1800 because 30 minutes contain 1800 seconds.
Detailed explanation:
Truncate timestamp to arbitrary intervals
The cast to timestamp makes me wonder about the actual data type of login_time? If it's timestamptz, the cast depends on your current time zone setting and sets you up for surprises if that setting changes. See:
How do I match an entire day to a datetime field?
Subtract hours from the now() function
Ignoring time zones altogether in Rails and PostgreSQL
Depending on the actual data type, and exact definition of your date boundaries, there is a more efficient way to phrase your WHERE clause.
You can change the column on which you're aggregating to use the minute too:
select
count(*) as logged_users,
CONCAT(EXTRACT(hour from login_time::timestamp), '-', CASE WHEN EXTRACT(minute from login_time::timestamp) < 30 THEN 0 ELSE 30 END) as HalfHour
from loginhistory
where login_time::date = '2021-04-21'
group by HalfHour
order by HalfHour;

Time Difference between two time columns in sql server

I have the issue in getting the minutes difference between two time columns in sql server.
Column1: Starttime
Column2: Endtime
These two are of the type nchar(10) , I converted them into time format in the below way and using the datediff function.
If the two columns have AM format or PM format, then difference of minutes is coming fine. But if i have start time is in PM format and End time as AM (SQL taking it as next day) format then i am getting negative minutes than expected.
select
dty_act_start_time,
dty_act_end_time,
datediff(minute, convert(varchar,dty_act_start_time,114),convert(varchar,dty_act_end_time,114))
from DB.Mydatabase;
Please let me know how to get the correct difference in minutes.
Just add 1440 minutes (number of minutes in 24 hours) if start time is greater than end time:
select
start_time_time,
end_time_time,
datediff(minute, start_time_time, end_time_time) + iif(start_time_time <= end_time_time, 0, 1440) as diff
from (
select
convert(time(0), dty_act_start_time, 114) as start_time_time,
convert(time(0), dty_act_end_time, 114) as end_time_time
from (values
('09:00am', '10:00pm'),
('10:00pm', '09:00am')
) tests(dty_act_start_time, dty_act_end_time)
) x
Result:
start_time_time | end_time_time | diff
09:00:00 | 22:00:00 | 780
22:00:00 | 09:00:00 | 660

Group records by time

I have a table containing a datetime column and some misc other columns. The datetime column represents an event happening. It can either contains a time (event happened at that time) or NULL (event didn't happen)
I now want to count the number of records happening in specific intervals (15 minutes), but do not know how to do that.
example:
id | time | foreign_key
1 | 2012-01-01 00:00:01 | 2
2 | 2012-01-01 00:02:01 | 4
3 | 2012-01-01 00:16:00 | 1
4 | 2012-01-01 00:17:00 | 9
5 | 2012-01-01 00:31:00 | 6
I now want to create a query that creates a result set similar to:
interval | COUNT(id)
2012-01-01 00:00:00 | 2
2012-01-01 00:15:00 | 2
2012-01-01 00:30:00 | 1
Is this possible in SQL or can anyone advise what other tools I could use? (e.g. exporting the data to a spreadsheet program would not be a problem)
Give this a try:
select datetime((strftime('%s', time) / 900) * 900, 'unixepoch') interval,
count(*) cnt
from t
group by interval
order by interval
Check the fiddle here.
I have limited SQLite background (and no practice instance), but I'd try grabbing the minutes using
strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
with the %M modifier (http://souptonuts.sourceforge.net/readme_sqlite_tutorial.html)
Then divide that by 15 and get the FLOOR of your quotient to figure out which quarter-hour you're in (e.g., 0, 1, 2, or 3)
cast(x as int)
Getting the floor value of a number in SQLite?
Strung together it might look something like:
Select cast( (strftime( 'YYYY-MM-DD HH:MI:SS', your_time_field, '%M') / 15) as int) from your_table
(you might need to cast before you divide by 15 as well, since strftime probably returns a string)
Then group by the quarter-hour.
Sorry I don't have exact syntax for you, but that approach should enable you to get the functional groupings, after which you can massage the output to make it look how you want.