PostgreSQL format lag column - postgresql

This query works great for finding the difference between successive rows:
select id, created_at, created_at - lag(created_at, 1)
over (order by created_at) as diff
from fistbumps where bumper_id = 2543
and created_at between '2012-01-11' and '2012-01-12' order by created_at;
...but the results come out like:
id | created_at | diff
--------+----------------------------+-----------------
197230 | 2012-01-11 00:04:31.774426 |
197231 | 2012-01-11 00:04:32.279181 | 00:00:00.504755
197232 | 2012-01-11 00:04:33.961665 | 00:00:01.682484
197233 | 2012-01-11 00:04:36.506685 | 00:00:02.54502
What would be really groovy is if I could format that diff column to just seconds and millis (e.g. 2.54502). I tried using date_trunc() and extract(), but I can't seem to get the syntax right.

The result of created_at - lag(create_at) is a value of type interval.
You can get the seconds of an interval using extract(epoch from interval_value)
So in your case it would be:
extract(epoch from (created_at - lag(created_at, 1)) )

Related

Calculate time difference over the first and the last table row

Within postgresql, I'm trying to write a query that calculates the time difference between a time stamp of the first row and a time stamp of the last row:
(select public."ImportLogs"."DateTimeStamp" as migration_start from public."ImportLogs" order by public."ImportLogs"."DateTimeStamp" asc limit 1)
union
(select public."ImportLogs"."DateTimeStamp" as migration_end from public."ImportLogs" order by public."ImportLogs"."DateTimeStamp" desc limit 1);
I tried to get the time difference between migration_start and migration_end, but I couldn't get it to work. How can I achieve this?
We can substract min(DateTimeStamp) from the max(DateTimeStamp)` and cast the difference as time.
select
cast(
max(DateTimeStamp)
- min(DateTimeStamp)
as time) TimeDiffernce
from ImportLogs
| timediffernce |
| :------------ |
| 00:00:10 |
db<>fiddle here

MySQL group by timestamp difference

I need to write mysql query which will group results by difference between timestamps.
Is it possible?
I have table with locations and every row has created_at (timestamp) and I want to group results by difference > 1min.
Example:
id | lat | lng | created_at
1. | ... | ... | 2020-05-03 06:11:35
2. | ... | ... | 2020-05-03 06:11:37
3. | ... | ... | 2020-05-03 06:11:46
4. | ... | ... | 2020-05-03 06:12:48
5. | ... | ... | 2020-05-03 06:12:52
Result of this data should be 2 groups (1,2,3) and (4,5)
It depends on what you actually want. If youw want to group together records that belong to the same minute, regardless of the difference with the previous record, then simple aggregation is enough:
select
date_format(created_at, '%Y-%m-%d %H:%i:00') date_minute,
min(id) min_id,
max(id) max_id,
min(created_at) min_created_at,
max(created_at) max_created_at,
count(*) no_records
from mytable
group by date_minute
On the other hand, if you want to build groups of consecutive records that have less than 1 minute gap in between, this is a gaps and islands problem. Here is on way to solve it using window functions (available in MySQL 8.0):
select
min(id) min_id,
max(id) max_id,
min(created_at) min_created_at,
max(created_at) max_created_at,
count(*) no_records
from (
select
t.*,
sum(case when created_at < lag_created_at + interval 1 minute then 0 else 1 end)
over(order by created_at) grp
from (
select
t.*,
lag(created_at) over(order by created_at) lag_created_at
from mytable t
) t
) t
group by grp

Get min/max value per day with epoch times in Postgres 8.4

I have a table with epoch values (one per minute, the epoch itself is in milliseconds) and temperatures.
select * from outdoor_temperature order by time desc;
time | value
---------------+-------
1423385340000 | 31.6
1423385280000 | 31.6
1423385220000 | 31.7
1423385160000 | 31.7
1423385100000 | 31.7
1423385040000 | 31.8
1423384980000 | 31.8
1423384920000 | 31.8
1423384860000 | 31.8
[...]
I want to get the lowest value (and highest, but that can be a separate query) that occurred in each day, and the specific time (preferably the original epoch time) when that occurred. I've managed to do it with date_trunc but that gives me the general day, rather than the specific time within that day:
select
date_trunc('day',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp,
min(value)
from outdoor_temperature
group by timestamp
order by min asc
limit 5;
timestamp | min
------------------------+------
2015-03-27 00:00:00+10 | 10.7
2015-03-28 00:00:00+10 | 10.8
2015-01-30 00:00:00+10 | 13.6
2015-03-17 00:00:00+10 | 14.0
2015-03-29 00:00:00+10 | 14.5
(5 rows)
Is there some sort of join magic I need to do (my join-fu is extremely weak), or am I attacking this from totally the wrong direction? I tried DISTINCT ON but didn't manage to even get that working.
You can start from this query:
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
which shows two columns, the first is "epoch" converted to the timestamp with "minute" precision.
Since you need to find the lowest/highest value for each day, would be nice to have also column with just a date rather than timestamp:
SELECT
x.timestamp::date AS a,
x.timestamp AS b,
temperature AS c
FROM (
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
) AS x
So now you have a date as "a" column, a timestamp as "b" column and the temperature value in the last, "c" column.
The last part is to use "order by" in conjunctionw ith "distinct on" expression. This is better than group by, because you're finding unique values of one column and see the associations of another:
select distinct on(y.a)
y.a,
y.b,
y.c
from (
SELECT
x.timestamp::date AS a,
x.timestamp AS b,
temperature AS c
FROM (
SELECT date_trunc('minute',TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000) * INTERVAL '1 second') as timestamp, value AS temperature from _outdoor_temperature
) AS x
) y
order by y.a, y.c
select day::date, min_value_timestamp, min_value, max_value_timestamp, max_value
from
(
select distinct on (1)
date_trunc('day', timestamp with time zone 'epoch' + time/1000 * interval '1 second') as day,
timestamp with time zone 'epoch' + (time/1000 * interval '1 second') as min_value_timestamp,
value as min_value
from outdoor_temperature
order by 1, 3
) s
inner join
(
select distinct on (1)
date_trunc('day', timestamp with time zone 'epoch' + time/1000 * interval '1 second') as day,
timestamp with time zone 'epoch' + (time/1000 * interval '1 second') as max_value_timestamp,
value as max_value
from outdoor_temperature
order by 1, 3 desc
) v using (day)
order by 1
Ok, thanks to #voycheck's suggestion I ended up adding another column of type date and populating that with just the date that corresponds to the time field, so the table looks like this:
Column | Type | Modifiers
--------+---------+-----------
time | bigint | not null
value | numeric |
date | date |
Indexes:
"outdoor_temperature_pkey" PRIMARY KEY, btree ("time")
"outdoor_temperature_date_idx" btree (date)
"outdoor_temperature_value_idx" btree (value)
Which then massively simplified and sped up the SQL query:
SELECT time, value FROM (
SELECT DISTINCT ON (date)
date, time, value
FROM outdoor_temperature
ORDER BY date, value desc
) t
ORDER BY t.value desc;

LAG function and GROUP BY

I have a table like this,
event_id | date
----------+------------------------
1703702 | 2013-06-25 07:50:57-04
3197588 | 2013-06-25 07:51:57-04
60894420 | 2013-06-25 07:52:57-04
60894420 | 2013-06-25 07:53:57-04
183503 | 2013-06-25 07:54:57-04
63116743 | 2013-06-25 07:55:57-04
63110451 | 2013-06-25 07:56:57-04
63116743 | 2013-06-25 07:57:57-04
63116743 | 2013-06-25 07:58:57-04
I'd like to apply the lag function but also a group by so I can find the time intervals between any particular event_id.
I'd like something like this:
SELECT event_id, difference
FROM (
SELECT event_id, date - lag(date) over (order by date) as
difference FROM table GROUP BY event_id
) t;
I cannot however use GROUP BY with the LAG function. I'd like a result similar to the following:
63116743, {120, 60}
60894420, {60}
...
...
So there was a 120s and 60s window between the events for the first id, and a 60s window for the second id.
Is there a way to do this? The output format is not too important as long as I can get it into an array in the end. I'm using Postgres 9.1
WITH diffs as (
SELECT
event_id,
date - lag(date) over (partition BY event_id ORDER BY date) as difference
FROM
TABLE
)
SELECT
event_id,
array_agg( difference ) as all_diffs
FROM
diffs
GROUP BY event_id;
Should work.

Grouping based on every N days in postgresql

I have a table that includes ID, date, values (temperature) and some other stuff. My table looks like this:
+-----+--------------+------------+
| ID | temperature | Date |
+-----+--------------+------------+
| 1 | 26.3 | 2012-02-05 |
| 2 | 27.8 | 2012-02-06 |
| 3 | 24.6 | 2012-02-07 |
| 4 | 29.6 | 2012-02-08 |
+-----+--------------+------------+
I want to perform aggregation queries like sum and mean for every 10 days.
I was wondering if it is possible in psql or not?
SQL Fiddle
select
"date",
temperature,
avg(temperature) over(order by "date" rows 10 preceding) mean
from t
order by "date"
select id,
temperature,
sum(temperature) over (order by "date" rows between 10 preceding and current row)
from the_table;
It might not exactly be what you want, as it will do a moving sum over the last 10 rows, which is not necessarily the same as the last 10 days.
Since Postgres 11, you can now use a range based on an interval
select id,
temperature,
avg(temperature) over (order by "date"
range between interval '10 days' preceding and current row)
from the_table;