Add hours to timestamp in Netezza based on other column - sql

I'm working in a Netezza SQL database. I have 2 columns:
DATETIME1: has the timestamp of transaction at UTC time
TIME_OFFSET: is an integer, showing the offset of the users' time zone from UTC. For example, users in UTC+1 have value 1.
What I would like to do is add the TIME_OFFSET column to the DATETIME1 column as an hour.
I created the following reproducible example:
SELECT *
FROM ADMIN.INTEGRAL_ADSCIENCE_1845
WITH my_table AS (
SELECT TIMESTAMP('2017-06-01 08:01:45') AS datetime1,
1 AS time_offset
UNION
SELECT TIMESTAMP('2017-06-01 08:03:45') AS datetime1,
2 AS time_offset
)
SELECT
DATETIME1,
TIME_OFFSET,
DATETIME1 + TIME_OFFSET AS simple_add,
DATETIME1 + INTERVAL '1 hour' AS add_one_hour
FROM my_table;
This creates the following output:
+---------------------+-------------+------------+---------------------+
| DATETIME1 | TIME_OFFSET | SIMPLE_ADD | ADD_ONE_HOUR |
+---------------------+-------------+------------+---------------------+
| 2017-06-01 08:01:45 | 1 | 2017-06-02 | 2017-06-01 09:01:45 |
| 2017-06-01 08:03:45 | 2 | 2017-06-03 | 2017-06-01 09:03:45 |
+---------------------+-------------+------------+---------------------+
But what I would like to have is adding 1 hour to first row and 2 hours to second row.
I'm aware of the mysql date_add() function, but I'm limited to Netezza unfortunately.

This should work for you.
WITH my_table AS (SELECT TIMESTAMP('2017-06-01 08:01:45') AS dttm
, 1 AS tm_offset
UNION
SELECT TIMESTAMP('2017-06-01 08:03:45') AS dttm
, 2 AS tm_offset)
SELECT dttm
, tm_offset
, dttm + tm_offset AS simple_add
, dttm + CAST(tm_offset || ' hour' AS INTERVAL)
FROM my_table;

Related

SQL (BigQuery) Grouping Runtime Per Day

I have the following data which I want to group into seconds per day in BigQuery.
Source Table:
+--------------+---------------------+---------------------+
| ComputerName | StartDatetime | EndDatetime |
+--------------+---------------------+---------------------+
| Computer1 | 2020-06-10T21:01:28 | 2020-06-10T21:20:19 |
+--------------+---------------------+---------------------+
| Computer1 | 2020-06-10T22:54:01 | 2020-06-11T05:21:48 |
+--------------+---------------------+---------------------+
| Computer2 | 2020-06-08T09:11:54 | 2020-06-10T11:36:27 |
+--------------+---------------------+---------------------+
I want to be able to visualise the data in the following way
+------------+--------------+------------------+
| Date | ComputerName | Runtime(Seconds) |
+------------+--------------+------------------+
| 2020-10-10 | Computer1 | 5089 |
+------------+--------------+------------------+
| 2020-10-11 | Computer1 | 19308 |
+------------+--------------+------------------+
| 2020-10-08 | Computer2 | 53285 |
+------------+--------------+------------------+
| 2020-10-09 | Computer2 | 86400 |
+------------+--------------+------------------+
| 2020-10-10 | Computer2 | 41787 |
+------------+--------------+------------------+
I am not too sure of the way I should approach this. Some input would be greatly appreciated.
This is an interval overlap problem. You can solve this by splitting each time period into separate days and then looking at the overlap for each day:
with t as (
select 'Computer1' as computername, datetime '2020-06-10T21:01:28' as startdatetime, datetime '2020-06-10T21:20:19' as enddatetime union all
select 'Computer1' as computername, datetime '2020-06-10T22:54:01' as startdatetime, datetime '2020-06-11T05:21:48' as enddatetime union all
select 'Computer2' as computername, datetime '2020-06-08T09:11:54' as startdatetime, datetime '2020-06-10T11:36:27' as enddatetime
)
select dte, t.computername,
sum(case when enddatetime >= dte and
startdatetime < date_add(dte, interval 1 day)
then datetime_diff(least(date_add(dte, interval 1 day), enddatetime),
greatest(dte, startdatetime),
second)
end) as runtime_seconds
from (select t.*,
generate_date_array(date(t.startdatetime), date(t.enddatetime), interval 1 day) gda
from t
) t cross join
unnest(gda) dte
group by dte, t.computername;
Below is for BigQuery Standard SQL
#standardSQL
select Date, ComputerName,
sum(datetime_diff(
least(datetime (Date + 1), EndDatetime),
greatest(datetime(Date), StartDatetime),
second
)) as Runtime_Seconds
from `project.dataset.table`,
unnest(generate_date_array(date(StartDatetime), date(EndDatetime))) Date
group by Date, ComputerName
if to apply to sample data in your question - as in below example
#standardSQL
with `project.dataset.table` as (
select 'Computer1' ComputerName, datetime '2020-06-10T21:01:28' StartDatetime, datetime '2020-06-10T21:20:19' EndDatetime union all
select 'Computer1', '2020-06-10T22:54:01', '2020-06-11T05:21:48' union all
select 'Computer2', '2020-06-08T09:11:54', '2020-06-10T11:36:27'
)
select Date, ComputerName,
sum(datetime_diff(
least(datetime (Date + 1), EndDatetime),
greatest(datetime(Date), StartDatetime),
second
)) as Runtime_Seconds
from `project.dataset.table`,
unnest(generate_date_array(date(StartDatetime), date(EndDatetime))) Date
group by Date, ComputerName
output is
Another option for BigQuery Standard SQL
Straightforward, "little silly" and almost logic-less option of just "stupidly" counting seconds in respective days - still looks like an option to me
#standardSQL
select Date, ComputerName,
countif(second >= timestamp(StartDatetime) and second < timestamp(EndDatetime)) as Runtime_Seconds
from `project.dataset.table`,
unnest(generate_date_array(date(StartDatetime), date(EndDatetime))) Date,
unnest(generate_timestamp_array(timestamp(Date + 1), timestamp(Date), interval -1 second)) second with offset
where offset > 0
group by Date, ComputerName
if applied to sample data from your question - output is

SQLite: Sum of differences between two dates group by every date

I have a SQLite database with start and stop datetimes
With the following SQL query I get the difference hours between start and stop:
SELECT starttime, stoptime, cast((strftime('%s',stoptime)-strftime('%s',starttime)) AS real)/60/60 AS diffHours FROM tracktime;
I need a SQL query, which delivers the sum of multiple timestamps, grouped by every day (also whole dates between timestamps).
The result should be something like this:
2018-08-01: 12 hours
2018-08-02: 24 hours
2018-08-03: 12 hours
2018-08-04: 0 hours
2018-08-05: 1 hours
2018-08-06: 14 hours
2018-08-07: 8 hours
You can try this, use CTE RECURSIVE make a calendar table for every date start time and end time, and do some calculation.
Schema (SQLite v3.18)
CREATE TABLE tracktime(
id int,
starttime timestamp,
stoptime timestamp
);
insert into tracktime values
(11,'2018-08-01 12:00:00','2018-08-03 12:00:00');
insert into tracktime values
(12,'2018-09-05 18:00:00','2018-09-05 19:00:00');
Query #1
WITH RECURSIVE cte AS (
select id,starttime,date(starttime,'+1 day') totime,stoptime
from tracktime
UNION ALL
SELECT id,
date(starttime,'+1 day'),
date(totime,'+1 day'),
stoptime
FROM cte
WHERE date(starttime,'+1 day') < stoptime
)
SELECT strftime('%Y-%m-%d', starttime),(strftime('%s',CASE
WHEN totime > stoptime THEN stoptime
ELSE totime
END) -strftime('%s',starttime))/3600 diffHour
FROM cte;
| strftime('%Y-%m-%d', starttime) | diffHour |
| ------------------------------- | -------- |
| 2018-08-01 | 12 |
| 2018-09-05 | 1 |
| 2018-08-02 | 24 |
| 2018-08-03 | 12 |
View on DB Fiddle

How to add number field to varchar field in oracle. varchar field is time in HH:MM:SS format

I have 2 columns
Start_Time (VARCHAR) Duration_in_sec (NUMBER)
12:03:11 220
11:05:33 345
I want to add col2 to col1 to get end time.
How do I do that I tried
Select TO_NUMBER(col1)+col2 as end_time from ABC.
This is giving me error. Can someone help me with right way.
This is the error I am getting which is straight forward but How to get the right number. I need to do some maniculation on col1 but I am not getting how to do that
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
You can convert the start time and duration both to intervals and then add the two intervals. That way you can handle when the duration is more than one day:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( Start_Time, Duration_in_sec ) AS
SELECT '12:03:11', 220 FROM DUAL UNION ALL
SELECT '11:05:33', 345 FROM DUAL UNION ALL
SELECT '23:59:59', 1 FROM DUAL;
Query 1:
SELECT t.*,
( TO_TIMESTAMP( start_time, 'HH24:MI:SS' )
- TO_TIMESTAMP( '00:00:00', 'HH24:MI:SS' )
) + NUMTODSINTERVAL( Duration_in_sec, 'SECOND' ) AS end_time
FROM table_name t
Results:
| START_TIME | DURATION_IN_SEC | END_TIME |
|------------|-----------------|--------------|
| 12:03:11 | 220 | 0 12:6:51.0 |
| 11:05:33 | 345 | 0 11:11:18.0 |
| 23:59:59 | 1 | 1 0:0:0.0 |
A better solution would be to store both the start time and duration as intervals; then you can just add the values:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name (
start_time INTERVAL DAY TO SECOND,
duration_in_sec INTERVAL DAY TO SECOND
);
INSERT INTO table_name
SELECT INTERVAL '12:03:11' HOUR TO SECOND, INTERVAL '220' SECOND FROM DUAL UNION ALL
SELECT INTERVAL '11:05:33' HOUR TO SECOND, INTERVAL '345' SECOND FROM DUAL UNION ALL
SELECT INTERVAL '23:59:59' HOUR TO SECOND, INTERVAL '1' SECOND FROM DUAL;
Query 1:
SELECT t.*,
start_time + Duration_in_sec AS end_time
FROM table_name t
Results:
| START_TIME | DURATION_IN_SEC | END_TIME |
|--------------|-----------------|--------------|
| 0 12:3:11.0 | 0 0:3:40.0 | 0 12:6:51.0 |
| 0 11:5:33.0 | 0 0:5:45.0 | 0 11:11:18.0 |
| 0 23:59:59.0 | 0 0:0:1.0 | 1 0:0:0.0 |
Here's one way, using the numToDSInterval function:
select
to_date(start_time,'HH24:MI:SS')+numToDSInterval(Duration_in_sec, 'second')
from time_seconds;
(Uses a table named "time_seconds")
To return just the time string:
select
to_char(
to_date(start_time,'HH24:MI:SS')+numToDSInterval(Duration_in_sec, 'second'), 'HH24:MI:SS'
)
from time_seconds;
So first, it converts the timestamp from a VARCHAR to a DATE, then it increments that DATE by your number of seconds using numToDSInterval.
I would add, though, that storing a time as a string seems like a bad idea. And are your times storied in 24-hour format? Or 12-hour with AM/PM? How can you be sure that your strings are parseable into Dates?
Etc.? You should be using the right datatypes for the right job.

Converting date into integer (1 to 365)

I have no idea if there is a function in postgres to do that, but how can I convert a date (yyyy-mm-dd) into the numeric correspondent in SQL?
E.g. table input
id | date
------+-------------
1 | 2013-01-01
2 | 2013-01-02
3 | 2013-02-01
Output
id | date
------+-------------
1 | 1
2 | 2
3 | 32
You are looking for the extract() function with the doy("Day Of Year") argument, not day ("day of the week"):
select id, extract(doy from "date")
from the_table;
Acording to this documentation an other option is to do something like:
SELECT id, DATE_PART('day', date - date_trunc('year', date)) + 1 as date
from table_name;
Here you can see a sql-fiddle.

Filling Out & Filtering Irregular Time Series Data

Using Postgresql 9.4, I am trying to craft a query on time series log data that logs new values whenever the value updates (not on a schedule). The log can update anywhere from several times a minute to once a day.
I need the query to accomplish the following:
Filter too much data by just selecting the first entry for the timestamp range
Fill in sparse data by using the last reading for the log value. For example, if I am grouping the data by hour and there was an entry at 8am with a log value of 10. Then the next entry isn't until 11am with a log value of 15, I would want the query to return something like this:
Timestamp | Value
2015-07-01 08:00 | 10
2015-07-01 09:00 | 10
2015-07-01 10:00 | 10
2015-07-01 11:00 | 15
I have got a query that accomplishes the first of these goals:
with time_range as (
select hour
from generate_series('2015-07-01 00:00'::timestamp, '2015-07-02 00:00'::timestamp, '1 hour') as hour
),
ranked_logs as (
select
date_trunc('hour', time_stamp) as log_hour,
log_val,
rank() over (partition by date_trunc('hour', time_stamp) order by time_stamp asc)
from time_series
)
select
time_range.hour,
ranked_logs.log_val
from time_range
left outer join ranked_logs on ranked_logs.log_hour = time_range.hour and ranked_logs.rank = 1;
But I can't figure out how to fill in the nulls where there is no value. I tried using the lag() feature of Postgresql's Window functions, but it didn't work when there were multiple nulls in a row.
Here's a SQLFiddle that demonstrates the issue:
http://sqlfiddle.com/#!15/f4d13/5/0
your columns are log_hour and first_vlue
with time_range as (
select hour
from generate_series('2015-07-01 00:00'::timestamp, '2015-07-02 00:00'::timestamp, '1 hour') as hour
),
ranked_logs as (
select
date_trunc('hour', time_stamp) as log_hour,
log_val,
rank() over (partition by date_trunc('hour', time_stamp) order by time_stamp asc)
from time_series
),
base as (
select
time_range.hour lh,
ranked_logs.log_val
from time_range
left outer join ranked_logs on ranked_logs.log_hour = time_range.hour and ranked_logs.rank = 1)
SELECT
log_hour, log_val, value_partition, first_value(log_val) over (partition by value_partition order by log_hour)
FROM (
SELECT
date_trunc('hour', base.lh) as log_hour,
log_val,
sum(case when log_val is null then 0 else 1 end) over (order by base.lh) as value_partition
FROM base) as q
UPDATE
this is what your query return
Timestamp | Value
2015-07-01 01:00 | 10
2015-07-01 02:00 | null
2015-07-01 03:00 | null
2015-07-01 04:00 | 15
2015-07-01 05:00 | nul
2015-07-01 06:00 | 19
2015-07-01 08:00 | 13
I want this result set to be split in groups like this
2015-07-01 01:00 | 10
2015-07-01 02:00 | null
2015-07-01 03:00 | null
2015-07-01 04:00 | 15
2015-07-01 05:00 | nul
2015-07-01 06:00 | 19
2015-07-01 08:00 | 13
and to assign to every row in a group the value of first row from that group (done by last select)
In this case, a method for obtaining the grouping is to create a column which holds the number of
not null values counted until current row and split by this value. (use of sum(case))
value | sum(case)
| 10 | 1 |
| null | 1 |
| null | 1 |
| 15 | 2 | <-- new not null, increment
| nul | 2 |
| 19 | 3 | <-- new not null, increment
| 13 | 4 | <-- new not null, increment
and now I can partion by sum(case)