A atualização incremental de Dynamic Table oferece suporte a funções de agregação básicas — COUNT, SUM, MIN/MAX e COUNT DISTINCT — além das funções estendidas listadas neste tópico.
Lista de funções compatíveis
|
Função |
Descrição |
Versão compatível |
|
Window functions para processamento TopN. Classificam linhas dentro de uma partição e filtram os N principais registros. Apenas ROW_NUMBER e RANK são compatíveis. Defina |
V4.2 e posterior |
|
|
Window functions que retornam o valor da linha seguinte ou anterior dentro de uma partição. São comuns no cálculo de deltas entre registros adjacentes, variações entre períodos e transições de estado. Especifique tanto PARTITION BY quanto ORDER BY. Apenas as formas de argumento único |
V5.0 e posterior |
|
|
COUNT, SUM, MIN/MAX, COUNT DISTINCT |
Funções de agregação básicas |
Todas as versões |
|
hg_id_encoding_int32 / hg_id_encoding_int64 |
Mapeiam um UID do tipo text para int32 ou int64 e gravam automaticamente o mapeamento em uma tabela de mapeamento de usuário. Ideais para calcular visitantes únicos (UV) em longos períodos com RoaringBitmap. |
V4.1 e posterior |
|
min_by / max_by |
Retornam o valor de uma coluna da linha com o valor mínimo ou máximo em outra coluna. |
V4.0 e posterior |
|
RB_BUILD_AGG |
Constrói um RoaringBitmap a partir de uma coluna int32 ou int64. |
V3.1 e posterior |
|
string_agg |
Concatena valores de coluna em uma string usando um delimitador. A sintaxe |
V3.1 e posterior |
|
array_agg |
Agrega valores de coluna em um array. A sintaxe |
V3.1 e posterior |
|
any_value |
Em uma consulta |
V3.1.5 e posterior |
ROW_NUMBER / RANK
O Hologres V4.2 e versões posteriores oferecem suporte às window functions ROW_NUMBER() e RANK() na atualização incremental de Dynamic Table. Use essas funções para particionar e classificar linhas e filtrar os N principais registros de cada partição. Esse é um padrão comum para materialização TopN em tempo real.
Sintaxe
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]
Argumentos:
PARTITION BY partition_column: Opcional. Agrupa linhas em partições antes da classificação.ORDER BY order_column [ASC|DESC]: Obrigatório. Define a ordem de classificação dentro de cada partição.rownum <= N: Obrigatório. Mantém apenas as N primeiras linhas de cada partição.
Notas de uso
Compatível com Hologres V4.2 e posterior.
Defina
refresh_modecomoautopara permitir que o Hologres derive automaticamente o modo incremental para a Dynamic Table.
Exemplo
O exemplo abaixo cria uma Dynamic Table que mantém os 3 pedidos de maior valor por product, com atualização incremental a cada 5 minutos.
-- 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;
LEAD / LAG
O Hologres V5.0 e versões posteriores oferecem suporte às window functions lead() e lag() no modo de atualização incremental. Essas funções retornam o valor da linha seguinte ou anterior dentro de uma partição ordenada. Elas são frequentes no cálculo de deltas entre registros adjacentes, variações entre períodos e transições de estado.
Sintaxe
SELECT [column_list],
{lead | lag}(<expr>) OVER (
PARTITION BY col1[, col2...]
ORDER BY col1 [ASC|DESC] [NULLS FIRST|NULLS LAST][, col2 ...]) AS <alias>
FROM table_name;
Parâmetros
expr: a coluna a ser lida. Essa coluna também deve aparecer na lista SELECT. Caso contrário, a atualização falhará. Para mais informações, consulte Usage notes.
PARTITION BY: obrigatório. As colunas usadas para particionamento. Várias colunas são compatíveis.
ORDER BY: obrigatório. As colunas usadas para ordenação. Várias colunas, ASC e DESC, bem como NULLS FIRST e NULLS LAST, são compatíveis.
Notas de uso
Compatível com Hologres V5.0 e posterior.
Tanto PARTITION BY quanto ORDER BY são obrigatórios.
Apenas as formas de argumento único
lead(expr)elag(expr)são compatíveis, o que significa que o offset é sempre 1. As sintaxeslead(expr, offset)elead(expr, offset, default)não são aceitas.A coluna de entrada de lead ou lag deve constar na lista SELECT. Por exemplo,
SELECT id, k, lead(price) OVER (...)falha durante a atualização e deve ser reescrita comoSELECT id, k, price, lead(price) OVER (...).As colunas de PARTITION BY e ORDER BY não podem usar tipos de ponto flutuante (float, float4, float8, real ou double precision). Para ordenar por valores decimais, utilize numeric ou decimal. Os tipos de chave compatíveis são int, bigint, smallint, numeric ou decimal, text ou varchar, date, timestamp, timestamptz e bool.
Garanta que as colunas ORDER BY sejam únicas dentro de cada partição. Se várias linhas em uma mesma partição compartilharem a mesma chave de ordenação, incluindo múltiplos valores NULL, a atualização incremental resolve o empate por meio de um número de linha interno. Esse comportamento difere da atualização completa e de consultas OLAP regulares, podendo gerar resultados divergentes. Ambos os resultados são válidos sob a semântica SQL. Para garantir determinismo, adicione uma coluna única ao ORDER BY como critério de desempate.
IGNORE NULLS e RESPECT NULLS não são compatíveis.
A primeira atualização constrói o estado completo e pode levar bastante tempo.
A duração de uma atualização incremental depende principalmente da proporção de partições afetadas pela mudança, e não do número de linhas alteradas. O desempenho é melhor quando as alterações se concentram em poucas partições. Se cada alteração abranger todas as partições, prefira a atualização completa. A atualização incremental também mantém uma tabela de estado adicional, cuja sobrecarga de armazenamento é significativamente maior que a da atualização completa. Considere isso no planejamento de capacidade.
Exemplo
O exemplo a seguir calcula a variação de valor entre dois eventos consecutivos para cada usuário.
-- Create the source table for user event details.
CREATE TABLE user_events (
event_id bigint,
user_id text,
event_ts timestamptz,
amount numeric(10,2)
);
INSERT INTO user_events VALUES
(1, 'u1', '2026-08-20 10:00:00+08', 100.00),
(2, 'u1', '2026-08-20 11:00:00+08', 150.00),
(3, 'u1', '2026-08-20 12:00:00+08', 120.00),
(4, 'u2', '2026-08-20 09:00:00+08', 80.00),
(5, 'u2', '2026-08-20 10:30:00+08', 95.00);
-- Create the Dynamic Table. The input column amount must appear in the SELECT list.
CREATE DYNAMIC TABLE user_amount_diff
WITH (
freshness = '5 minutes',
auto_refresh_mode = 'incremental'
) AS
SELECT
event_id,
user_id,
event_ts,
amount,
lag(amount) OVER (PARTITION BY user_id ORDER BY event_ts) AS prev_amount,
amount - COALESCE(lag(amount) OVER (PARTITION BY user_id ORDER BY event_ts), 0) AS diff
FROM user_events;
SELECT * FROM user_amount_diff ORDER BY user_id, event_ts;
O resultado é apresentado a seguir.
event_id | user_id | event_ts | amount | prev_amount | diff
----------+---------+------------------------+--------+-------------+--------
1 | u1 | 2026-08-20 10:00:00+08 | 100.00 | | 100.00
2 | u1 | 2026-08-20 11:00:00+08 | 150.00 | 100.00 | 50.00
3 | u1 | 2026-08-20 12:00:00+08 | 120.00 | 150.00 | -30.00
4 | u2 | 2026-08-20 09:00:00+08 | 80.00 | | 80.00
5 | u2 | 2026-08-20 10:30:00+08 | 95.00 | 80.00 | 15.00
(5 rows)
hg_id_encoding_int32 / hg_id_encoding_int64
As funções hg_id_encoding_int32 e hg_id_encoding_int64 mapeiam uma coluna UID do tipo text para int32 ou int64 e gravam automaticamente o mapeamento em uma tabela de mapeamento de usuário. Use essas funções com a atualização incremental de Dynamic Table e RoaringBitmap para calcular UVs em longos períodos.
Para um exemplo completo de ponta a ponta, consulte Calculating UV over arbitrarily long periods using Hologres Dynamic Tables.
Sintaxe
hg_id_encoding_int4(<user_id>, '<mapping_tablename>')
hg_id_encoding_int8(<user_id>, '<mapping_tablename>')
Argumentos
|
Argumento |
Tipo |
Descrição |
|
|
text |
A coluna UID a ser mapeada. Valores NULL não são compatíveis — ocorrerá um erro se NULL for passado. |
|
|
text |
O nome da tabela de mapeamento de usuário. Crie esta tabela antes de chamar a função. |
Comportamento
Grava novos mapeamentos de UID para inteiro na tabela de mapeamento de usuário. Se um UID já existir na tabela, o mapeamento existente é preservado e nenhuma duplicata é inserida.
Notas de uso
Compatível com Hologres V4.1 e posterior.
A tabela de mapeamento de usuário deve ter uma chave primária e exatamente um campo Serial (além da chave primária).
Apenas chaves primárias de coluna única do tipo text são compatíveis.
Exemplo
-- 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
As funções min_by e max_by retornam o valor de uma coluna proveniente da linha com o valor mínimo ou máximo em outra coluna.
Sintaxe
min_by(expr1, expr2)
max_by(expr1, expr2)
Argumentos
|
Argumento |
Descrição |
|
|
A coluna usada para comparação (encontra o valor mínimo ou máximo). |
|
|
A coluna cujo valor será retornado da linha correspondente. |
Retorno
O valor de expr1 da linha onde expr2 atinge seu mínimo (min_by) ou máximo (max_by).
Notas de uso
Compatível com Hologres V4.0 e posterior.
Exemplo
O exemplo a seguir cria uma Dynamic Table que rastreia o primeiro e o último evento de cada usuário, com base nos timestamps dos eventos.
-- 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
A função string_agg concatena valores não nulos de uma coluna em uma única string, separados por um delimitador constante.
Sintaxe
string_agg([distinct] column_expr, const_expr)
Argumentos
|
Argumento |
Tipo |
Descrição |
|
|
text, char ou varchar |
A coluna a ser agregada. |
|
|
constante text |
O delimitador inserido entre os valores concatenados. |
Notas de uso
A cláusula
ORDER BYnão é compatível.A sintaxe
string_agg([distinct])exige Hologres V3.1.10 ou posterior.A função básica
string_aggestá disponível no Hologres V3.1 e posterior.
Exemplo
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
A função array_agg coleta valores não nulos de uma coluna em um array.
Sintaxe
array_agg([distinct] expr)
Argumentos
|
Argumento |
Tipo |
Descrição |
|
|
boolean, qualquer tipo numérico, text ou bytea |
A coluna a ser agregada em um array. |
Notas de uso
A cláusula
ORDER BYnão é compatível.A sintaxe
array_agg([distinct])exige Hologres V3.1.10 ou posterior.A função básica
array_aggestá disponível no Hologres V3.1 e posterior.
Exemplo
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
Em uma consulta GROUP BY, a função any_value retorna um valor não determinístico de cada grupo de agregação.
Sintaxe
any_value(expr)
Argumentos
|
Argumento |
Tipo |
Descrição |
|
|
int ou binary |
A coluna da qual um valor será retornado. |
Notas de uso
Compatível com Hologres V3.1.5 e posterior.
expraceita apenas os tipos int e binary.O valor retornado é não determinístico.
Exemplo
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;