Postgresql - Avg just minutes and seconds? - postgresql

Im running an aggregate query that's returning just two columns, a name and timez.
timez is currently in the format of MI:SS, stored as varchar. In my query, I want to get the average minutes and seconds of time, but of course if I cast the column to a timestamp, the avg() function doesn't work on it. I tried dividing the timestamps by count(1) which doesn't work either as timestamps can't be divided. Below is what I ideally wanted.
SELECT name, avg(to_timestamp(timez,'MI:SS'))
FROM logs_table
GROUP BY name

Just cast the timez column to a time type before applying avg:
SELECT name, avg(CAST(timez AS time))
FROM logs_table
GROUP BY name;

Related

discarding milliseconds from the average time calculated

Here is my code:
SELECT cluster_id, AVG(min_per_imei_cluster::TIME) as avg_time
FROM arrival
group by cluster_id
The avg_time column gives values with milliseconds and beyond. How do I truncate or round to the nearest second?
I tried using
AVG(min_per_imei_cluster::TIME)::timestamp(0)
but got the following error:
SQL Error [42846]: ERROR: cannot cast type interval to timestamp without time zone
It looks like you can use the date_trunc function to specify the level of precision that you want. So in this instance, you would do date_trunc('second',min_per_imei_cluster).

clickhouse downsample into OHLC time bar intervals

For a table e.g. containing a date, price timeseries with prices every e.g. millisecond, how can this be downsampled into groups of open high low close (ohlc) rows with time interval e.g. minute?
While option with arrays will work, the simplest option here is to use use combination of group by timeintervals with min, max, argMin, argMax aggregate functions.
SELECT
id,
minute,
max(value) AS high,
min(value) AS low,
avg(value) AS avg,
argMin(value, timestamp) AS first,
argMax(value, timestamp) AS last
FROM security
GROUP BY id, toStartOfMinute(timestamp) AS minute
ORDER BY minute
In ClickHouse you solve this kind of problem with arrays. Let's assume a table like the following:
CREATE TABLE security (
timestamp DateTime,
id UInt32,
value Float32
)
ENGINE=MergeTree
PARTITION BY toYYYYMM(timestamp)
ORDER BY (id, timestamp)
You can downsample to one-minute intervals with a query like the following:
SELECT
id, minute, max(value) AS high, min(value) AS low, avg(value) AS avg,
arrayElement(arraySort((x,y)->y,
groupArray(value), groupArray(timestamp)), 1) AS first,
arrayElement(arraySort((x,y)->y,
groupArray(value), groupArray(timestamp)), -1) AS last
FROM security
GROUP BY id, toStartOfMinute(timestamp) AS minute
ORDER BY minute
The trick is to use array functions. Here's how to decode the calls:
groupArray gathers column data within the group into an array.
arraySort sorts the values using the timestamp order. We use a lambda function to provide the timestamp array as the sorting key for the first array of values.
arrayElement allows us to pick the first and last elements respectively.
To keep the example simple I used DateTime for the timestamp which only samples at 1 second intervals. You can use a UInt64 column to get any precision you want. I added an average to my query to help check results.

Find days between dates

I am looking to subtract 2 dates to get the number of days in between. However, the columns are defined as "timestamp without time zone". I'm not sure how to get a whole integer.
I have a stored procedure with this code:
v_days_between_changes := DATE_PATH('day',CURRENT_DATE - v_prev_rec.date_updated)::integer;
But I get this error:
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT DATE_PATH('day',CURRENT_DATE - v_prev_rec.date_updated)::integer
Any help would be great.
You can compute the difference between the dates, which returns an interval. Then, extract the number of days from this interval.
WITH src(dt1,dt2) AS (select '1/1/2019'::timestamp without time zone, CURRENT_DATE )
select EXTRACT(day FROM dt2-dt1) nbdays
from src;
nbdays
-----------
98

query to fetch records between two date and time

I have been using postgreSQL. My table has 3 columns date, time and userId. I have to find out records between the given date and time frame. Since date and time columns are different, 'BETWEEN' clause is not providing valid results
Combine the two columns into a single timestamp by adding the time to the date:
select *
from some_table
where date_column + time_column
between timestamp '2017-06-14 17:30:00' and timestamp '2017-06-19 08:26:00';
Note that this will not use an index on date_column or time_column. You would need to create an index on that expression. Or better: use a single column defined as timestamp instead.

Calculate the sum of time column in PostgreSql

Can anyone suggest me, the easiest way to find summation of time field in POSTGRESQL. i just find a solution for MYSQL but i need the POSTGRESQL version.
MYSQL: https://stackoverflow.com/questions/3054943/calculate-sum-time-with-mysql
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(timespent))) FROM myTable;
Demo Data
id time
1 1:23:23
2 4:00:23
3 9:23:23
Desired Output
14:47:09
What you want, is not possible. But you probably misunderstood the time type: it represents a precise time-point in a day. It doesn't make much sense, to add two (or more) times. f.ex. '14:00' + '14:00' = '28:00' (but there are no 28th hour in a day).
What you probably want, is interval (which represents time intervals; hours, minutes, or even years). sum() supports interval arguments.
If you use intervals, it's just that simple:
SELECT sum(interval_col) FROM my_table;
Although, if you stick to the time type (but you have no reason to do that), you can cast it to interval to calculate with it:
SELECT sum(time_col::interval) FROM my_table;
But again, the result will be interval, because time values cannot exceed the 24th hour in a day.
Note: PostgreSQL will even do the cast for you, so sum(time_col) should work too, but the result is interval in this case too.
I tried this solution on sql fieddle:
link
Table creation:
CREATE TABLE time_table (
id integer, time time
);
Insert data:
INSERT INTO time_table (id,time) VALUES
(1,'1:23:23'),
(2,'4:00:23'),
(3,'9:23:23')
query the data:
SELECT
sum(s.time)
FROM
time_table s;
If you need to calculate sum of some field, according another field, you can do this:
select
keyfield,
sum(time_col::interval) totaltime
FROM myTable
GROUP by keyfield
Output example:
keyfield; totaltime
"Gabriel"; "10:00:00"
"John"; "36:00:00"
"Joseph"; "180:00:00"
Data type of totaltime is interval.