Dynamic Table incremental refresh supports basic aggregate functions—COUNT, SUM, MIN/MAX, and COUNT DISTINCT—as well as the extended functions listed in this topic.
Function support list
| Function | Description | Supported version |
|---|---|---|
| ROW_NUMBER / RANK | Window functions for TopN processing. Ranks rows within a partition and filters the top N records. Only ROW_NUMBER and RANK are supported. Set refresh_mode to auto to enable automatic incremental refresh. |
V4.2 and later |
| COUNT, SUM, MIN/MAX, COUNT DISTINCT | Basic aggregate functions | All versions |
| hg_id_encoding_int32 / hg_id_encoding_int64 | Maps a UID of the text type to int32 or int64, and auto-writes the mapping to a user mapping table. Commonly used to calculate unique visitors (UV) over long periods with RoaringBitmap. | V4.1 and later |
| min_by / max_by | Returns the value of one column from the row with the minimum or maximum value in another column. | V4.0 and later |
| RB_BUILD_AGG | Builds a RoaringBitmap from an int32 or int64 column. | V3.1 and later |
| string_agg | Concatenates column values into a string using a delimiter. string_agg([distinct]) syntax requires V3.1.10 or later. |
V3.1 and later |
| array_agg | Aggregates column values into an array. array_agg([distinct]) syntax requires V3.1.10 or later. |
V3.1 and later |
| any_value | In a GROUP BY query, returns a non-deterministic value from each group. Supports only the int and binary types. |
V3.1.5 and later |
ROW_NUMBER / RANK
Hologres V4.2 and later support ROW_NUMBER() and RANK() window functions in Dynamic Table incremental refresh. Use these functions to partition and rank rows, then filter the top N records from each partition—a common pattern for real-time TopN materialization.
Syntax
SELECT [column_list]
FROM (
SELECT [column_list],
ROW_NUMBER() OVER ([PARTITION BY partition_column[, ...]]
ORDER BY order_column [ASC|DESC][, ...]) AS rownum
FROM table_name)
WHERE rownum <= N [AND conditions]
Arguments:
-
PARTITION BY partition_column: Optional. Groups rows into partitions before ranking. -
ORDER BY order_column [ASC|DESC]: Required. Defines the ranking order within each partition. -
rownum <= N: Required. Retains only the top N rows from each partition.
Usage notes
-
Supported in Hologres V4.2 and later.
-
Only
ROW_NUMBER()andRANK()are supported. Other window functions—such asDENSE_RANK,LAG, andLEAD—are not supported. -
Set
refresh_modetoautoto let Hologres automatically derive incremental mode for the Dynamic Table.
Example
The following example creates a Dynamic Table that maintains the top 3 orders by amount for each product, refreshed incrementally every 5 minutes.
-- Create the source table
CREATE TABLE orders (
order_id bigint,
product_id bigint,
amount bigint
);
INSERT INTO orders
SELECT i, i % 100, (random() * 1000000)::bigint
FROM generate_series(1, 10000) i;
-- Create the Dynamic Table for TopN
CREATE DYNAMIC TABLE top3_orders
WITH (
freshness = '5 minutes',
auto_refresh_mode = 'incremental'
) AS
SELECT order_id, product_id, amount
FROM (
SELECT order_id, product_id, amount,
ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY amount DESC) AS rownum
FROM orders)
WHERE rownum <= 3;
-- Query results for a specific product
SELECT * FROM top3_orders WHERE product_id = 1;
hg_id_encoding_int32 / hg_id_encoding_int64
hg_id_encoding_int32 and hg_id_encoding_int64 map a UID column of the text type to int32 or int64, and automatically write the mapping to a user mapping table. Use these functions with Dynamic Table incremental refresh and RoaringBitmap to calculate UVs over long periods.
For an end-to-end example, see Calculating UV over arbitrarily long periods using Hologres Dynamic Tables.
Syntax
hg_id_encoding_int4(<user_id>, '<mapping_tablename>')
hg_id_encoding_int8(<user_id>, '<mapping_tablename>')
Arguments
| Argument | Type | Description |
|---|---|---|
user_id |
text | The UID column to map. NULL values are not supported—an error occurs if NULL is passed. |
mapping_tablename |
text | The name of the user mapping table. Create this table before calling the function. |
Behavior
Writes new UID-to-integer mappings to the user mapping table. If a UID already exists in the table, the existing mapping is preserved and no duplicate is inserted.
Usage notes
-
Supported in Hologres V4.1 and later.
-
The user mapping table must have a primary key and exactly one Serial field (besides the primary key).
-
Only a single-column primary key of the text type is supported.
Example
-- Create the source table
CREATE TABLE base_table(user_id text);
INSERT INTO base_table VALUES('a');
-- Create the user mapping table
CREATE TABLE uid_mapping(user_id text PRIMARY KEY, id serial);
-- Map UIDs to integers and write mappings to uid_mapping
SELECT user_id, hg_id_encoding_int4(user_id, 'uid_mapping') AS res
FROM base_table;
-- Query the mapping table to verify
-- user_id | id
-- --------+----
-- a | 1
min_by / max_by
min_by and max_by return the value of one column from the row with the minimum or maximum value in another column.
Syntax
min_by(expr1, expr2)
max_by(expr1, expr2)
Arguments
| Argument | Description |
|---|---|
expr2 |
The column used for comparison (finds the minimum or maximum value). |
expr1 |
The column whose value is returned from the matching row. |
Returns
The value of expr1 from the row where expr2 is at its minimum (min_by) or maximum (max_by).
Usage notes
Supported in Hologres V4.0 and later.
Example
The following example creates a Dynamic Table that tracks each user's first and last events, based on event timestamps.
-- Create the source table
DROP TABLE IF EXISTS detail;
CREATE TABLE detail (
userid text,
event_id text,
create_time timestamptz
);
INSERT INTO detail(userid, event_id, create_time) VALUES
('user_1', 'e1', '2024-12-20 10:00:00+08'),
('user_1', 'e2', '2024-12-20 11:30:00+08'),
('user_1', 'e3', '2024-12-21 09:15:00+08'),
('user_2', 'e4', '2024-12-20 08:05:00+08'),
('user_2', 'e5', '2024-12-22 14:20:00+08'),
('user_3', 'e6', '2024-12-21 16:45:00+08');
-- Create the Dynamic Table
DROP TABLE IF EXISTS detail_user_first_last_event;
CREATE DYNAMIC TABLE detail_user_first_last_event
WITH (
auto_refresh_mode = 'incremental',
computing_resource = 'local',
freshness = '3 minutes'
)
AS
SELECT
userid,
min_by(event_id, create_time) AS first_event_id,
max_by(event_id, create_time) AS last_event_id,
date_trunc('day', max(create_time))::date AS dt
FROM detail
GROUP BY userid;
string_agg
string_agg concatenates non-null values from a column into a single string, separated by a constant delimiter.
Syntax
string_agg([distinct] column_expr, const_expr)
Arguments
| Argument | Type | Description |
|---|---|---|
column_expr |
text, char, or varchar | The column to aggregate. |
const_expr |
text constant | The delimiter placed between concatenated values. |
Usage notes
-
The
ORDER BYclause is not supported. -
string_agg([distinct])syntax requires Hologres V3.1.10 or later. -
Basic
string_aggis supported in Hologres V3.1 and later.
Example
CREATE DYNAMIC TABLE string_agg_test_dt
WITH (
freshness = '3 minutes',
refresh_mode = 'incremental')
AS
SELECT day,
string_agg(gameversion, ',') AS gameversion_list
FROM base_table GROUP BY day;
array_agg
array_agg collects non-null values from a column into an array.
Syntax
array_agg([distinct] expr)
Arguments
| Argument | Type | Description |
|---|---|---|
expr |
boolean, any numeric type, text, or bytea | The column to aggregate into an array. |
Usage notes
-
The
ORDER BYclause is not supported. -
array_agg([distinct])syntax requires Hologres V3.1.10 or later. -
Basic
array_aggis supported in Hologres V3.1 and later.
Example
CREATE DYNAMIC TABLE array_agg_test_dt
WITH (
freshness = '3 minutes',
refresh_mode = 'incremental')
AS
SELECT day,
array_agg(gameversion) AS gameversion_list
FROM base_table GROUP BY day;
any_value
In a GROUP BY query, any_value returns a non-deterministic value from each aggregation group.
Syntax
any_value(expr)
Arguments
| Argument | Type | Description |
|---|---|---|
expr |
int or binary | The column from which to return a value. |
Usage notes
-
Supported in Hologres V3.1.5 and later.
-
exprsupports only the int and binary types. -
The return value is non-deterministic.
Example
CREATE DYNAMIC TABLE dt_t0
WITH (
freshness = '1 minutes',
auto_refresh_mode = 'auto'
)
AS
SELECT a, any_value(c), sum(b) FROM t0 GROUP BY a;