mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-17 11:03:36 +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
|
-- [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
|
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
|
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
|
-- utility functions
|
||||||
CREATE OR REPLACE FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMP) RETURNS TIMESTAMP
|
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
|
subspace_store.c
|
||||||
tablespace.c
|
tablespace.c
|
||||||
time_bucket.c
|
time_bucket.c
|
||||||
time_bucket_ng.c
|
|
||||||
time_utils.c
|
time_utils.c
|
||||||
custom_type_cache.c
|
custom_type_cache.c
|
||||||
trigger.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);
|
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_timestamp_bucket(PG_FUNCTION_ARGS);
|
||||||
extern TSDLLEXPORT Datum ts_timestamptz_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 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 */
|
#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
|
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;
|
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
|
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
|
\set ON_ERROR_STOP 1
|
||||||
-- infinity
|
-- infinity
|
||||||
SELECT timescaledb_experimental.time_bucket_ng('1 year', 'infinity' :: date) AS result;
|
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
|
Tue Jun 01 00:00:00 2021 EDT
|
||||||
(1 row)
|
(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
|
-- N days / weeks buckets
|
||||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d), 'YYYY-MM-DD') AS d1,
|
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', '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 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 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
|
\set ON_ERROR_STOP 1
|
||||||
|
|
||||||
-- infinity
|
-- 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' :: 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;
|
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
|
-- N days / weeks buckets
|
||||||
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
SELECT to_char(d, 'YYYY-MM-DD') AS d,
|
||||||
to_char(timescaledb_experimental.time_bucket_ng('1 day', d), 'YYYY-MM-DD') AS d1,
|
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;
|
DROP TABLE conditions CASCADE;
|
||||||
NOTICE: drop cascades to 3 other objects
|
NOTICE: drop cascades to 3 other objects
|
||||||
NOTICE: drop cascades to 2 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;
|
ORDER BY bucket;
|
||||||
|
|
||||||
DROP TABLE conditions CASCADE;
|
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