mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 18:43:18 +08:00
Support seconds, minutes, and hours in time_bucket_ng()
As a future replacement for time_bucket(), time_bucket_ng() should support seconds, minutes, and hours. This patch adds this support. The implementation is the same as for time_bucket(). Timezones are not yet supported.
This commit is contained in:
parent
78a21f412b
commit
99f7a2122f
@ -24,10 +24,10 @@
|
||||
-- [2]: https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-TIMEZONES
|
||||
--
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts DATE) RETURNS DATE
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng_date' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts DATE, origin DATE) RETURNS DATE
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
||||
AS '@MODULE_PATHNAME@', 'ts_time_bucket_ng_date' LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
|
||||
|
||||
-- utility functions
|
||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMP) RETURNS TIMESTAMP
|
||||
|
@ -48,7 +48,6 @@ set(SOURCES
|
||||
subspace_store.c
|
||||
tablespace.c
|
||||
time_bucket.c
|
||||
time_bucket_ng.c
|
||||
time_utils.c
|
||||
custom_type_cache.c
|
||||
trigger.c
|
||||
|
@ -292,3 +292,168 @@ ts_time_bucket_by_type(int64 interval, int64 timestamp, Oid timestamp_type)
|
||||
|
||||
return ts_time_value_to_internal(time_bucketed, timestamp_type);
|
||||
}
|
||||
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng_timestamp);
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DateADT ts_date;
|
||||
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
||||
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
|
||||
|
||||
if (interval->time != 0)
|
||||
{
|
||||
if (interval->month != 0)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("interval can't combine months with minutes or hours")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle minutes, hours and days.
|
||||
*/
|
||||
Timestamp origin = (PG_NARGS() > 2 ? PG_GETARG_TIMESTAMP(2) : DEFAULT_ORIGIN);
|
||||
Timestamp result;
|
||||
int64 period = get_interval_period_timestamp_units(interval);
|
||||
|
||||
if (TIMESTAMP_NOT_FINITE(timestamp))
|
||||
PG_RETURN_TIMESTAMP(timestamp);
|
||||
|
||||
TIME_BUCKET_TS(period, timestamp, result, origin);
|
||||
|
||||
PG_RETURN_TIMESTAMP(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Discard any time information and work with the date.
|
||||
*/
|
||||
ts_date = DatumGetDateADT(DirectFunctionCall1(timestamp_date, PG_GETARG_DATUM(1)));
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
DateADT result;
|
||||
DateADT origin = DatumGetDateADT(DirectFunctionCall1(timestamp_date, PG_GETARG_DATUM(2)));
|
||||
result = DatumGetDateADT(DirectFunctionCall3(ts_time_bucket_ng_date,
|
||||
PG_GETARG_DATUM(0),
|
||||
DateADTGetDatum(ts_date),
|
||||
DateADTGetDatum(origin)));
|
||||
return DirectFunctionCall1(date_timestamp, DateADTGetDatum(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
DateADT result;
|
||||
result = DatumGetDateADT(DirectFunctionCall2(ts_time_bucket_ng_date,
|
||||
PG_GETARG_DATUM(0),
|
||||
DateADTGetDatum(ts_date)));
|
||||
return DirectFunctionCall1(date_timestamp, DateADTGetDatum(result));
|
||||
}
|
||||
}
|
||||
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng_timestamptz);
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng_timestamptz(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DateADT result;
|
||||
Datum interval = PG_GETARG_DATUM(0);
|
||||
DateADT ts_date = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, PG_GETARG_DATUM(1)));
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
DateADT origin = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, PG_GETARG_DATUM(2)));
|
||||
result = DatumGetDateADT(DirectFunctionCall3(ts_time_bucket_ng_date,
|
||||
interval,
|
||||
DateADTGetDatum(ts_date),
|
||||
DateADTGetDatum(origin)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = DatumGetDateADT(
|
||||
DirectFunctionCall2(ts_time_bucket_ng_date, interval, DateADTGetDatum(ts_date)));
|
||||
}
|
||||
|
||||
return DirectFunctionCall1(date_timestamptz, DateADTGetDatum(result));
|
||||
}
|
||||
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng_date);
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng_date(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
||||
DateADT date = PG_GETARG_DATEADT(1);
|
||||
DateADT origin_date = 0;
|
||||
int origin_year = 2000, origin_month = 1, origin_day = 1;
|
||||
int year, month, day;
|
||||
int delta, bucket_number;
|
||||
|
||||
if ((interval->time != 0) || ((interval->month != 0) && (interval->day != 0)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("interval must be either days and weeks, or months and years")));
|
||||
}
|
||||
|
||||
if ((interval->month == 0) && (interval->day == 0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("interval must be at least one day")));
|
||||
}
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
origin_date = PG_GETARG_DATUM(2);
|
||||
j2date(origin_date + POSTGRES_EPOCH_JDATE, &origin_year, &origin_month, &origin_day);
|
||||
}
|
||||
|
||||
if ((origin_day != 1) && (interval->month != 0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be the first day of the month")));
|
||||
}
|
||||
|
||||
if (DATE_NOT_FINITE(date))
|
||||
PG_RETURN_DATEADT(date);
|
||||
|
||||
if (interval->month != 0)
|
||||
{
|
||||
/* Handle months and years */
|
||||
|
||||
j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
|
||||
|
||||
if ((year < origin_year) || ((year == origin_year) && (month < origin_month)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be before the given date")));
|
||||
}
|
||||
|
||||
delta = (year * 12 + month) - (origin_year * 12 + origin_month);
|
||||
bucket_number = delta / interval->month;
|
||||
year = origin_year + (bucket_number * interval->month) / 12;
|
||||
month =
|
||||
(((origin_year * 12 + (origin_month - 1)) + (bucket_number * interval->month)) % 12) +
|
||||
1;
|
||||
day = 1;
|
||||
|
||||
date = date2j(year, month, day) - POSTGRES_EPOCH_JDATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle days and weeks */
|
||||
|
||||
if (date < origin_date)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be before the given date")));
|
||||
}
|
||||
|
||||
delta = date - origin_date;
|
||||
bucket_number = delta / interval->day;
|
||||
date = bucket_number * interval->day;
|
||||
}
|
||||
|
||||
PG_RETURN_DATEADT(date);
|
||||
}
|
||||
|
@ -18,5 +18,8 @@ extern TSDLLEXPORT Datum ts_date_bucket(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_timestamp_bucket(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_timestamptz_bucket(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT int64 ts_time_bucket_by_type(int64 interval, int64 timestamp, Oid type);
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_date(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamptz(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif /* TIMESCALEDB_TIME_BUCKET_H */
|
||||
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* This file and its contents are licensed under the Apache License 2.0.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-APACHE for a copy of the license.
|
||||
*/
|
||||
#include <postgres.h>
|
||||
#include <utils/date.h>
|
||||
#include <utils/datetime.h>
|
||||
#include <utils/fmgrprotos.h>
|
||||
|
||||
#include "time_bucket_ng.h"
|
||||
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng);
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng_timestamp);
|
||||
TS_FUNCTION_INFO_V1(ts_time_bucket_ng_timestamptz);
|
||||
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DateADT result;
|
||||
Datum interval = PG_GETARG_DATUM(0);
|
||||
DateADT ts_date = DatumGetDateADT(DirectFunctionCall1(timestamp_date, PG_GETARG_DATUM(1)));
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
DateADT origin = DatumGetDateADT(DirectFunctionCall1(timestamp_date, PG_GETARG_DATUM(2)));
|
||||
result = DatumGetDateADT(DirectFunctionCall3(ts_time_bucket_ng,
|
||||
interval,
|
||||
DateADTGetDatum(ts_date),
|
||||
DateADTGetDatum(origin)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = DatumGetDateADT(
|
||||
DirectFunctionCall2(ts_time_bucket_ng, interval, DateADTGetDatum(ts_date)));
|
||||
}
|
||||
|
||||
return DirectFunctionCall1(date_timestamp, DateADTGetDatum(result));
|
||||
}
|
||||
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng_timestamptz(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DateADT result;
|
||||
Datum interval = PG_GETARG_DATUM(0);
|
||||
DateADT ts_date = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, PG_GETARG_DATUM(1)));
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
DateADT origin = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, PG_GETARG_DATUM(2)));
|
||||
result = DatumGetDateADT(DirectFunctionCall3(ts_time_bucket_ng,
|
||||
interval,
|
||||
DateADTGetDatum(ts_date),
|
||||
DateADTGetDatum(origin)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = DatumGetDateADT(
|
||||
DirectFunctionCall2(ts_time_bucket_ng, interval, DateADTGetDatum(ts_date)));
|
||||
}
|
||||
|
||||
return DirectFunctionCall1(date_timestamptz, DateADTGetDatum(result));
|
||||
}
|
||||
|
||||
TSDLLEXPORT Datum
|
||||
ts_time_bucket_ng(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Interval *interval = PG_GETARG_INTERVAL_P(0);
|
||||
DateADT date = PG_GETARG_DATEADT(1);
|
||||
DateADT origin_date = 0; // 2000-01-01
|
||||
int origin_year = 2000, origin_month = 1, origin_day = 1;
|
||||
int year, month, day;
|
||||
int delta, bucket_number;
|
||||
|
||||
if ((interval->time != 0) || ((interval->month != 0) && (interval->day != 0)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("interval must be either days and weeks, or months and years")));
|
||||
}
|
||||
|
||||
if ((interval->month == 0) && (interval->day == 0))
|
||||
{
|
||||
/*
|
||||
* This will be fixed in future versions of ts_time_bucket_ng().
|
||||
* The reason why it's not yet implemented is that we want to start
|
||||
* experimenting with variable-sized buckets as soon as possible.
|
||||
* We know that fixed-sized buckets work OK and adding corresponding
|
||||
* logic will be trivial.
|
||||
*/
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("interval must be at least one day")));
|
||||
}
|
||||
|
||||
if (PG_NARGS() > 2)
|
||||
{
|
||||
origin_date = PG_GETARG_DATUM(2);
|
||||
j2date(origin_date + POSTGRES_EPOCH_JDATE, &origin_year, &origin_month, &origin_day);
|
||||
}
|
||||
|
||||
if ((origin_day != 1) && (interval->month != 0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be the first day of the month")));
|
||||
}
|
||||
|
||||
if (DATE_NOT_FINITE(date))
|
||||
PG_RETURN_DATEADT(date);
|
||||
|
||||
if (interval->month != 0)
|
||||
{
|
||||
/* Handle months and years */
|
||||
|
||||
j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
|
||||
|
||||
if ((year < origin_year) || ((year == origin_year) && (month < origin_month)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be before the given date")));
|
||||
}
|
||||
|
||||
delta = (year * 12 + month) - (origin_year * 12 + origin_month);
|
||||
bucket_number = delta / interval->month;
|
||||
year = origin_year + (bucket_number * interval->month) / 12;
|
||||
month =
|
||||
(((origin_year * 12 + (origin_month - 1)) + (bucket_number * interval->month)) % 12) +
|
||||
1;
|
||||
day = 1;
|
||||
|
||||
date = date2j(year, month, day) - POSTGRES_EPOCH_JDATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle days and weeks */
|
||||
|
||||
if (date < origin_date)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("origin must be before the given date")));
|
||||
}
|
||||
|
||||
delta = date - origin_date;
|
||||
bucket_number = delta / interval->day;
|
||||
date = bucket_number * interval->day;
|
||||
}
|
||||
|
||||
PG_RETURN_DATEADT(date);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* This file and its contents are licensed under the Apache License 2.0.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-APACHE for a copy of the license.
|
||||
*/
|
||||
#ifndef TIMESCALEDB_DATE_TRUNC_H
|
||||
#define TIMESCALEDB_DATE_TRUNC_H
|
||||
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamp(PG_FUNCTION_ARGS);
|
||||
extern TSDLLEXPORT Datum ts_time_bucket_ng_timestamptz(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif /* TIMESCALEDB_DATE_TRUNC_H */
|
@ -1238,6 +1238,8 @@ SELECT timescaledb_experimental.time_bucket_ng('1 month', '2000-01-02' :: date,
|
||||
ERROR: origin must be before the given date
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 day', '2000-01-02' :: date, origin => '2001-01-01') AS result;
|
||||
ERROR: origin must be before the given date
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month 3 hours', '2021-11-22' :: timestamp) AS result;
|
||||
ERROR: interval can't combine months with minutes or hours
|
||||
\set ON_ERROR_STOP 1
|
||||
-- infinity
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', 'infinity' :: date) AS result;
|
||||
@ -1271,6 +1273,48 @@ SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timesta
|
||||
Tue Jun 01 00:00:00 2021 EDT
|
||||
(1 row)
|
||||
|
||||
-- Make sure time_bucket_ng() supports seconds, minutes, and hours.
|
||||
-- We happen to know that the internal implementation is the same
|
||||
-- as for time_bucket(), thus there is no reason to execute all the tests
|
||||
-- we already have for time_bucket(). These two functions will most likely
|
||||
-- be merged eventually anyway.
|
||||
SELECT timescaledb_experimental.time_bucket_ng('30 seconds', '2021-07-12 12:34:56' :: timestamp) AS result;
|
||||
result
|
||||
--------------------------
|
||||
Mon Jul 12 12:34:30 2021
|
||||
(1 row)
|
||||
|
||||
SELECT timescaledb_experimental.time_bucket_ng('15 minutes', '2021-07-12 12:34:56' :: timestamp) AS result;
|
||||
result
|
||||
--------------------------
|
||||
Mon Jul 12 12:30:00 2021
|
||||
(1 row)
|
||||
|
||||
SELECT timescaledb_experimental.time_bucket_ng('6 hours', '2021-07-12 12:34:56' :: timestamp) AS result;
|
||||
result
|
||||
--------------------------
|
||||
Mon Jul 12 12:00:00 2021
|
||||
(1 row)
|
||||
|
||||
-- Same as above, but with provided 'origin' argument.
|
||||
SELECT timescaledb_experimental.time_bucket_ng('30 seconds', '2021-07-12 12:34:56' :: timestamp, origin => '2021-07-12 12:10:00') AS result;
|
||||
result
|
||||
--------------------------
|
||||
Mon Jul 12 12:34:30 2021
|
||||
(1 row)
|
||||
|
||||
SELECT timescaledb_experimental.time_bucket_ng('15 minutes', '2021-07-12 12:34:56' :: timestamp, origin => '2021-07-12 12:10:00') AS result;
|
||||
result
|
||||
--------------------------
|
||||
Mon Jul 12 12:25:00 2021
|
||||
(1 row)
|
||||
|
||||
SELECT timescaledb_experimental.time_bucket_ng('6 hours', '2021-07-12 12:34:56' :: timestamp, origin => '2021-07-12 12:10:00') AS result;
|
||||
result
|
||||
--------------------------
|
||||
Mon Jul 12 12:10:00 2021
|
||||
(1 row)
|
||||
|
||||
-- N days / weeks buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d), 'YYYY-MM-DD') AS d1,
|
||||
|
@ -609,6 +609,7 @@ SELECT timescaledb_experimental.time_bucket_ng('0 days', '2001-02-03' :: date) A
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month', '2001-02-03' :: date, origin => '2000-01-02') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month', '2000-01-02' :: date, origin => '2001-01-01') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 day', '2000-01-02' :: date, origin => '2001-01-01') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 month 3 hours', '2021-11-22' :: timestamp) AS result;
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- infinity
|
||||
@ -620,6 +621,20 @@ SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timesta
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamp, origin => '2021-06-01') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', '2021-11-22' :: timestamptz, origin => '2021-06-01') AS result;
|
||||
|
||||
-- Make sure time_bucket_ng() supports seconds, minutes, and hours.
|
||||
-- We happen to know that the internal implementation is the same
|
||||
-- as for time_bucket(), thus there is no reason to execute all the tests
|
||||
-- we already have for time_bucket(). These two functions will most likely
|
||||
-- be merged eventually anyway.
|
||||
SELECT timescaledb_experimental.time_bucket_ng('30 seconds', '2021-07-12 12:34:56' :: timestamp) AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('15 minutes', '2021-07-12 12:34:56' :: timestamp) AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('6 hours', '2021-07-12 12:34:56' :: timestamp) AS result;
|
||||
|
||||
-- Same as above, but with provided 'origin' argument.
|
||||
SELECT timescaledb_experimental.time_bucket_ng('30 seconds', '2021-07-12 12:34:56' :: timestamp, origin => '2021-07-12 12:10:00') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('15 minutes', '2021-07-12 12:34:56' :: timestamp, origin => '2021-07-12 12:10:00') AS result;
|
||||
SELECT timescaledb_experimental.time_bucket_ng('6 hours', '2021-07-12 12:34:56' :: timestamp, origin => '2021-07-12 12:10:00') AS result;
|
||||
|
||||
-- N days / weeks buckets
|
||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d), 'YYYY-MM-DD') AS d1,
|
||||
|
@ -53,3 +53,89 @@ ORDER BY bucket;
|
||||
DROP TABLE conditions CASCADE;
|
||||
NOTICE: drop cascades to 3 other objects
|
||||
NOTICE: drop cascades to 2 other objects
|
||||
-- Make sure seconds, minutes, and hours can be used with caggs ('origin' is not
|
||||
-- currently supported in caggs).
|
||||
CREATE TABLE conditions(
|
||||
tstamp TIMESTAMP NOT NULL,
|
||||
city text NOT NULL,
|
||||
temperature INT NOT NULL);
|
||||
SELECT create_hypertable(
|
||||
'conditions', 'tstamp',
|
||||
chunk_time_interval => INTERVAL '1 day'
|
||||
);
|
||||
create_hypertable
|
||||
-------------------------
|
||||
(3,public,conditions,t)
|
||||
(1 row)
|
||||
|
||||
INSERT INTO conditions (tstamp, city, temperature) VALUES
|
||||
('2021-06-14 12:30:00', 'Moscow', 26),
|
||||
('2021-06-14 12:30:10', 'Moscow', 22),
|
||||
('2021-06-14 12:30:20', 'Moscow', 24),
|
||||
('2021-06-14 12:30:30', 'Moscow', 24),
|
||||
('2021-06-14 12:30:40', 'Moscow', 27),
|
||||
('2021-06-14 12:30:50', 'Moscow', 28),
|
||||
('2021-06-14 12:31:10', 'Moscow', 30),
|
||||
('2021-06-14 12:31:20', 'Moscow', 31),
|
||||
('2021-06-14 12:31:30', 'Moscow', 34),
|
||||
('2021-06-14 12:31:40', 'Moscow', 34),
|
||||
('2021-06-14 12:31:50', 'Moscow', 34),
|
||||
('2021-06-14 12:32:00', 'Moscow', 32),
|
||||
('2021-06-14 12:32:10', 'Moscow', 32),
|
||||
('2021-06-14 12:32:20', 'Moscow', 31);
|
||||
CREATE MATERIALIZED VIEW conditions_summary_30sec
|
||||
WITH (timescaledb.continuous) AS
|
||||
SELECT city,
|
||||
timescaledb_experimental.time_bucket_ng('30 seconds', tstamp) AS bucket,
|
||||
MIN(temperature),
|
||||
MAX(temperature)
|
||||
FROM conditions
|
||||
GROUP BY city, bucket;
|
||||
NOTICE: refreshing continuous aggregate "conditions_summary_30sec"
|
||||
CREATE MATERIALIZED VIEW conditions_summary_1min
|
||||
WITH (timescaledb.continuous) AS
|
||||
SELECT city,
|
||||
timescaledb_experimental.time_bucket_ng('1 minute', tstamp) AS bucket,
|
||||
MIN(temperature),
|
||||
MAX(temperature)
|
||||
FROM conditions
|
||||
GROUP BY city, bucket;
|
||||
NOTICE: refreshing continuous aggregate "conditions_summary_1min"
|
||||
CREATE MATERIALIZED VIEW conditions_summary_1hour
|
||||
WITH (timescaledb.continuous) AS
|
||||
SELECT city,
|
||||
timescaledb_experimental.time_bucket_ng('1 hour', tstamp) AS bucket,
|
||||
MIN(temperature),
|
||||
MAX(temperature)
|
||||
FROM conditions
|
||||
GROUP BY city, bucket;
|
||||
NOTICE: refreshing continuous aggregate "conditions_summary_1hour"
|
||||
SELECT city, to_char(bucket, 'YYYY-MM-DD HH:mi:ss'), min, max FROM conditions_summary_30sec ORDER BY bucket;
|
||||
city | to_char | min | max
|
||||
--------+---------------------+-----+-----
|
||||
Moscow | 2021-06-14 12:30:00 | 22 | 26
|
||||
Moscow | 2021-06-14 12:30:30 | 24 | 28
|
||||
Moscow | 2021-06-14 12:31:00 | 30 | 31
|
||||
Moscow | 2021-06-14 12:31:30 | 34 | 34
|
||||
Moscow | 2021-06-14 12:32:00 | 31 | 32
|
||||
(5 rows)
|
||||
|
||||
SELECT city, to_char(bucket, 'YYYY-MM-DD HH:mi:ss'), min, max FROM conditions_summary_1min ORDER BY bucket;
|
||||
city | to_char | min | max
|
||||
--------+---------------------+-----+-----
|
||||
Moscow | 2021-06-14 12:30:00 | 22 | 28
|
||||
Moscow | 2021-06-14 12:31:00 | 30 | 34
|
||||
Moscow | 2021-06-14 12:32:00 | 31 | 32
|
||||
(3 rows)
|
||||
|
||||
SELECT city, to_char(bucket, 'YYYY-MM-DD HH:mi:ss'), min, max FROM conditions_summary_1hour ORDER BY bucket;
|
||||
city | to_char | min | max
|
||||
--------+---------------------+-----+-----
|
||||
Moscow | 2021-06-14 12:00:00 | 22 | 34
|
||||
(1 row)
|
||||
|
||||
DROP TABLE conditions CASCADE;
|
||||
NOTICE: drop cascades to 9 other objects
|
||||
NOTICE: drop cascades to table _timescaledb_internal._hyper_4_18_chunk
|
||||
NOTICE: drop cascades to table _timescaledb_internal._hyper_5_19_chunk
|
||||
NOTICE: drop cascades to table _timescaledb_internal._hyper_6_20_chunk
|
||||
|
@ -45,3 +45,64 @@ FROM conditions_summary_weekly
|
||||
ORDER BY bucket;
|
||||
|
||||
DROP TABLE conditions CASCADE;
|
||||
|
||||
-- Make sure seconds, minutes, and hours can be used with caggs ('origin' is not
|
||||
-- currently supported in caggs).
|
||||
CREATE TABLE conditions(
|
||||
tstamp TIMESTAMP NOT NULL,
|
||||
city text NOT NULL,
|
||||
temperature INT NOT NULL);
|
||||
|
||||
SELECT create_hypertable(
|
||||
'conditions', 'tstamp',
|
||||
chunk_time_interval => INTERVAL '1 day'
|
||||
);
|
||||
|
||||
INSERT INTO conditions (tstamp, city, temperature) VALUES
|
||||
('2021-06-14 12:30:00', 'Moscow', 26),
|
||||
('2021-06-14 12:30:10', 'Moscow', 22),
|
||||
('2021-06-14 12:30:20', 'Moscow', 24),
|
||||
('2021-06-14 12:30:30', 'Moscow', 24),
|
||||
('2021-06-14 12:30:40', 'Moscow', 27),
|
||||
('2021-06-14 12:30:50', 'Moscow', 28),
|
||||
('2021-06-14 12:31:10', 'Moscow', 30),
|
||||
('2021-06-14 12:31:20', 'Moscow', 31),
|
||||
('2021-06-14 12:31:30', 'Moscow', 34),
|
||||
('2021-06-14 12:31:40', 'Moscow', 34),
|
||||
('2021-06-14 12:31:50', 'Moscow', 34),
|
||||
('2021-06-14 12:32:00', 'Moscow', 32),
|
||||
('2021-06-14 12:32:10', 'Moscow', 32),
|
||||
('2021-06-14 12:32:20', 'Moscow', 31);
|
||||
|
||||
CREATE MATERIALIZED VIEW conditions_summary_30sec
|
||||
WITH (timescaledb.continuous) AS
|
||||
SELECT city,
|
||||
timescaledb_experimental.time_bucket_ng('30 seconds', tstamp) AS bucket,
|
||||
MIN(temperature),
|
||||
MAX(temperature)
|
||||
FROM conditions
|
||||
GROUP BY city, bucket;
|
||||
|
||||
CREATE MATERIALIZED VIEW conditions_summary_1min
|
||||
WITH (timescaledb.continuous) AS
|
||||
SELECT city,
|
||||
timescaledb_experimental.time_bucket_ng('1 minute', tstamp) AS bucket,
|
||||
MIN(temperature),
|
||||
MAX(temperature)
|
||||
FROM conditions
|
||||
GROUP BY city, bucket;
|
||||
|
||||
CREATE MATERIALIZED VIEW conditions_summary_1hour
|
||||
WITH (timescaledb.continuous) AS
|
||||
SELECT city,
|
||||
timescaledb_experimental.time_bucket_ng('1 hour', tstamp) AS bucket,
|
||||
MIN(temperature),
|
||||
MAX(temperature)
|
||||
FROM conditions
|
||||
GROUP BY city, bucket;
|
||||
|
||||
SELECT city, to_char(bucket, 'YYYY-MM-DD HH:mi:ss'), min, max FROM conditions_summary_30sec ORDER BY bucket;
|
||||
SELECT city, to_char(bucket, 'YYYY-MM-DD HH:mi:ss'), min, max FROM conditions_summary_1min ORDER BY bucket;
|
||||
SELECT city, to_char(bucket, 'YYYY-MM-DD HH:mi:ss'), min, max FROM conditions_summary_1hour ORDER BY bucket;
|
||||
|
||||
DROP TABLE conditions CASCADE;
|
||||
|
Loading…
x
Reference in New Issue
Block a user