- Categorias:
AT | BEFORE¶
A cláusula AT ou BEFORE é usada para o Snowflake Time Travel. Em uma consulta, ela é especificada na cláusula FROM imediatamente após o nome da tabela e determina o ponto no passado do qual os dados históricos são solicitados para o objeto:
A palavra-chave AT especifica que a solicitação inclui quaisquer alterações feitas por uma instrução ou transação com um carimbo de data/hora igual ao parâmetro especificado.
A palavra-chave BEFORE especifica que o pedido se refere a um ponto imediatamente anterior ao parâmetro especificado. Este ponto no tempo é imediatamente anterior à conclusão da instrução, identificada por seu ID de consulta. Para obter mais informações, consulte Como usar a cláusula BEFORE.
Para obter mais informações, consulte Compreensão e uso do Time Travel.
- Consulte também:
Sintaxe¶
SELECT ...
FROM ...
{
AT( { TIMESTAMP => <timestamp> | OFFSET => <time_difference> | STATEMENT => <id> | STREAM => '<name>' } ) |
BEFORE( STATEMENT => <id> )
}
[ ... ]
Parâmetros¶
TIMESTAMP => timestamp
Especifica uma data e hora exatas a serem usadas para o Time Travel. O valor deve ser explicitamente convertido para um tipo de dados TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZ ou TIMESTAMP_TZ.
Se nenhuma conversão explícita for especificada, o carimbo de data/hora na cláusula AT será tratado como um carimbo de data/hora com o fuso horário UTC (equivalente a TIMESTAMP_NTZ). Usar o tipo de dados TIMESTAMP para uma conversão explícita também pode fazer com que o valor seja tratado como um valor TIMESTAMP_NTZ. Para obter mais detalhes, consulte Tipos de dados de data e hora.
OFFSET => time_difference
Especifica a diferença em segundos do tempo atual a ser usado para o Time Travel, na forma
-N
ondeN
pode ser uma expressão inteira ou aritmética (por exemplo,-120
é 120 segundos,-30*60
é 1800 segundos ou 30 minutos).STATEMENT => id
Especifica a ID de consulta de uma instrução a ser usada como ponto de referência para o Time Travel. Este parâmetro oferece suporte a qualquer instrução de um dos seguintes tipos:
DML (por exemplo, INSERT, UPDATE, DELETE)
TCL (transação BEGIN, COMMIT)
SELECT
A ID da consulta deve fazer referência a uma consulta que tenha sido executada nos últimos 14 dias. Se a ID da consulta fizer referência a uma consulta com mais de 14 dias, o seguinte erro é retornado:
Error: statement <query_id> not found
Para contornar esta limitação, use o carimbo de data/hora para a consulta referenciada.
STREAM => 'name'
Especifica o identificador (ou seja, nome) de um fluxo existente na tabela ou exibição consultada. O offset atual no fluxo é usado como o ponto
AT
no tempo para retornar os dados de alteração para o objeto de origem.Essa palavra-chave é suportada somente ao criar um fluxo (usando CREATE STREAM) ou ao consultar dados de modificação (usando a cláusula CHANGES). Para obter exemplos, consulte esses tópicos.
Como usar o parâmetro AT TIMESTAMP¶
Na cláusula AT, é possível especificar a palavra-chave TIMESTAMP seguida por uma cadeia de caracteres que representa um carimbo de data/hora e uma conversão explícita opcional para o tipo de dados TIMESTAMP, TIMESTAMP_TZ, TIMESTAMP_LTZ ou TIMESTAMP_NTZ. Os exemplos a seguir são todos válidos:
AT ( TIMESTAMP => '2024-06-05 12:30:00'::TIMESTAMP_LTZ )
AT ( TIMESTAMP => '2024-06-05 12:30:00'::TIMESTAMP )
AT ( TIMESTAMP => '2024-06-05 12:30:00' )
Se nenhuma conversão explícita for especificada, o carimbo de data/hora na cláusula AT será tratado como um carimbo de data/hora com o fuso horário UTC (equivalente a TIMESTAMP_NTZ). Usar o tipo de dados TIMESTAMP para uma conversão explícita também pode fazer com que o valor seja tratado como um valor TIMESTAMP_NTZ, conforme discutido em Tipos de dados de data e hora.
A conversão explícita que você escolher afeta os resultados das consultas de Time Travel porque os carimbos de data/hora são interpretados em relação ao fuso horário atual da sessão e ao valor do parâmetro TIMESTAMP_TYPE_MAPPING. Para obter mais detalhes sobre esse comportamento, veja Consultando dados de Time Travel em uma sessão com um fuso horário diferente de UTC.
Por exemplo, você está executando consultas em uma sessão SQL onde o fuso horário atual é America/Los_Angeles
, e TIMESTAMP_TYPE_MAPPING está definido como TIMESTAMP_NTZ
. Crie uma tabela e insira imediatamente duas linhas:
CREATE OR REPLACE TABLE tt1 (c1 INT, c2 INT);
INSERT INTO tt1 VALUES(1,2);
INSERT INTO tt1 VALUES(2,3);
Verifique a hora de criação da tabela com um comando SHOW TABLES:
SHOW TERSE TABLES LIKE 'tt1';
+-------------------------------+------+-------+---------------+----------------+
| created_on | name | kind | database_name | schema_name |
|-------------------------------+------+-------+---------------+----------------|
| 2024-06-05 15:25:35.557 -0700 | TT1 | TABLE | TRAVEL_DB | TRAVEL_SCHEMA |
+-------------------------------+------+-------+---------------+----------------+
Observe o deslocamento de fuso horário na coluna created_on
. Cinco minutos depois, insira outra linha:
INSERT INTO tt1 VALUES(3,4);
Agora execute a seguinte consulta de Time Travel, esperando que ela retorne as duas primeiras linhas:
SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:29:00'::TIMESTAMP);
000707 (02000): Time travel data is not available for table TT1. The requested time is either beyond the allowed time travel period or before the object creation time.
A consulta falha porque o fuso horário da sessão é UTC, e a conversão explícita para TIMESTAMP respeita esse fuso horário. Portanto, presume-se que a tabela foi criada após o carimbo de data/hora especificado. Para resolver esse problema, execute a consulta novamente com uma conversão explícita para TIMESTAMP_LTZ (fuso horário local):
SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:29:00'::TIMESTAMP_LTZ);
+----+----+
| C1 | C2 |
|----+----|
| 1 | 2 |
| 2 | 3 |
+----+----+
Como esperado, a consulta retorna as duas primeiras linhas inseridas. Por fim, execute a mesma consulta, mas especifique um carimbo de data/hora um pouco posterior:
SELECT * FROM tt1 at(TIMESTAMP => '2024-06-05 15:31:00'::TIMESTAMP_LTZ);
+----+----+
| C1 | C2 |
|----+----|
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
+----+----+
Esta consulta retorna todas as três linhas, considerando o último carimbo de data/hora.
Como usar a cláusula BEFORE¶
O parâmetro STATEMENT na cláusula BEFORE deve se referir a uma consulta de ID. O ponto no passado usado por Time Travel é imediatamente anterior à instrução para aquele ID de consulta ser concluído, e não antes da instrução ser iniciada. Se consultas simultâneas confirmarem modificações nos dados entre o início e o fim da instrução, essas alterações serão incluídas nos resultados.
Por exemplo, as seguintes instruções estão sendo executadas na tabela my_table
em paralelo em dois threads separados:
Hora |
Thread |
Operação |
Fase |
Descrição |
---|---|---|---|---|
|
1 |
INSERT INTO my_table(id) VALUE(1) |
Início |
Inserir inicia a execução realizando as verificações necessárias. |
|
1 |
INSERT INTO my_table(id) VALUE(1) |
Fim |
Inserir |
|
1 |
DELETE FROM my_table |
Início |
Excluir identifica a lista de registros a serem excluídos (id=1). |
|
2 |
INSERT INTO my_table(id) VALUE(2) |
Início |
Inserir inicia a execução realizando as verificações necessárias. |
|
2 |
INSERT INTO my_table(id) VALUE(2) |
Fim |
Inserir |
|
2 |
SELECT * FROM my_table |
Fim |
O thread |
|
1 |
DELETE FROM my_table |
Fim |
Excluir atualizações |
|
1 |
SELECT * FROM my_table BEFORE(STATEMENT => LAST_QUERY_ID()) |
Fim |
A instrução SELECT usa o Time Travel para recuperar dados históricos anteriores à conclusão da operação de exclusão. Os resultados incluem a linha da 2ª instrução de inserção que ocorreu simultaneamente no thread |
Como solução alternativa, você pode usar um parâmetro TIMESTAMP que especifica um ponto no tempo imediatamente antes do início da instrução.
Notas de uso¶
Os dados em Snowflake são identificados por carimbos de data/hora que podem diferir um pouco do valor exato do tempo do sistema.
O valor para TIMESTAMP ou OFFSET deve ser uma expressão constante.
A menor resolução de tempo para TIMESTAMP é de milissegundos.
Se os dados solicitados estiverem além do período de retenção de Time Travel (o padrão é 1 dia), a instrução falha.
Além disso, se os dados solicitados estiverem dentro do período de retenção do Time Travel, mas não houver dados históricos disponíveis (por exemplo, se o período de retenção foi prorrogado), a instrução falha.
Se o tempo do Time Travel especificado for no momento ou antes do momento em que o objeto foi criado, a instrução falha. Consulte Como usar o parâmetro AT TIMESTAMP.
Ao acessar os dados históricos da tabela, os resultados incluem as colunas, os valores padrão etc. da definição atual da tabela. O mesmo se aplica a exibições não materializadas. Por exemplo, se você alterar uma tabela para adicionar uma coluna, a consulta de dados históricos antes do momento em que a coluna foi adicionada retornará resultados que incluem a nova coluna.
Os dados históricos têm os mesmos requisitos de controle de acesso que os dados atuais. Quaisquer alterações são aplicadas retroativamente.
As cláusulas AT e BEFORE não oferecem suporte à seleção de dados históricos de um CTE.
Por exemplo, a seguinte consulta não é suportada:
WITH mycte AS (SELECT mytable.* FROM mytable) SELECT * FROM mycte AT(TIMESTAMP => '2024-03-13 13:56:09.553 +0100'::TIMESTAMP_TZ);
No entanto, essas cláusulas são suportadas em uma consulta em uma cláusula WITH. Por exemplo, a seguinte consulta é suportada:
WITH mycte AS (SELECT * FROM mytable AT(TIMESTAMP => '2024-03-13 13:56:09.553 +0100'::TIMESTAMP_TZ)) SELECT * FROM mycte;
Consultas de Time Travel em tabelas híbridas têm as seguintes limitações:
Somente o parâmetro TIMESTAMP é compatível com a cláusula AT. Os parâmetros OFFSET, STATEMENT e STREAM não são compatíveis.
O valor do parâmetro TIMESTAMP deve ser o mesmo para todas as tabelas que pertencem ao mesmo banco de dados. Se as tabelas pertencerem a bancos de dados diferentes, valores TIMESTAMP diferentes poderão ser usados.
A cláusula BEFORE não é compatível.
Solução de problemas¶
Erro |
Time travel data is not available for table <tablename>
|
---|---|
Causa |
Em alguns casos, isto é causado pelo uso de uma cadeia de caracteres onde é esperado um carimbo de data/hora. |
Solução |
Converter a cadeia de caracteres em um carimbo de data/hora. ... AT(TIMESTAMP => '2018-07-27 12:00:00') -- fails
... AT(TIMESTAMP => '2018-07-27 12:00:00'::TIMESTAMP) -- succeeds
|
Exemplos¶
Selecionar os dados históricos de uma tabela usando um carimbo de data/hora específico: Nos dois primeiros exemplos, que usam o parâmetro TIMESTAMP, my_table
poderia ser uma tabela padrão ou uma tabela híbrida.
SELECT * FROM my_table AT(TIMESTAMP => 'Wed, 26 Jun 2024 09:20:00 -0700'::TIMESTAMP_LTZ);
SELECT * FROM my_table AT(TIMESTAMP => TO_TIMESTAMP(1432669154242, 3));
Selecionar dados históricos de uma tabela de 5 minutos atrás:
SELECT * FROM my_table AT(OFFSET => -60*5) AS T WHERE T.flag = 'valid';
Selecionar dados históricos de uma tabela até, sem incluir, quaisquer alterações feitas pela transação especificada:
SELECT * FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');
Retornar a diferença nos dados da tabela resultante da transação especificada:
SELECT oldt.* ,newt.*
FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS oldt
FULL OUTER JOIN my_table AT(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS newt
ON oldt.id = newt.id
WHERE oldt.id IS NULL OR newt.id IS NULL;
O exemplo a seguir executa uma consulta de junção Time Travel em duas tabelas no mesmo banco de dados, uma das quais é uma tabela híbrida. A mesma expressão TIMESTAMP deve ser usada para ambas as tabelas.
SELECT *
FROM db1.public.htt1
AT(TIMESTAMP => '2024-06-05 17:50:00'::TIMESTAMP_LTZ) h
JOIN db1.public.tt1
AT(TIMESTAMP => '2024-06-05 17:50:00'::TIMESTAMP_LTZ) t
ON h.c1=t.c1;