O contexto está se conectando a um banco de dados Postgres de um servidor de descanso.
Para considerar um exemplo hipotético representativo: gostaria de obter uma lista de nomes em que a data de criação da conta é mais antiga/mais recente que um valor arbitrário.
Na consulta de exemplo abaixo, a estrutura da tabela é simples - name
é do tipo text
e creation_date
é do tipo timestamp
. Então, quando eu faço algo como
server_pg_module:query("select name from new_table where
current_timestamp - creation_date < '6 days'")
funciona bem. Mas o que eu realmente quero fazer é obter esse valor do 6 days
servidor. Então eu tento algo como
server_pg_module:query("select name from new_table where
current_timestamp - timestamp < $1", ["6 days"]
ele lança um erro. Eu tentei '6 days'
, "'6 days'"
e algumas outras misturas, todos os erros de lançamento. Então, para verificar, adicionei uma nova coluna interval
do tipo interval
e tentei uma consulta como
server_pg_module:query("insert into new_table (name, interval) values ($1, '3 day')", ["fooo"]).
que funciona, mas
server_pg_module:query("insert into new_table (name, interval) values ($1, $2)", ["fooo", "3 days"]).
rompe. Para uma boa medida, além das misturas "'3 days'"
mencionadas acima, eu também tentei $2::interval
(o que não tenho certeza se é legítimo), mas não funciona.
Assim, acredito que possa ter algo a ver com a expressão de um intervalo em uma consulta de parâmetro ou algo peculiar sobre o módulo que estou usando. Qualquer idéia sobre o que causa o problema e como fazer esse tipo de coisa seria apreciada. Ou pode ser que o problema não seja com pg, mas com o módulo, então eu tenho que resolvê-lo em outro lugar.
Versão do Postgres: 10.x
O módulo que estou usando é pgo (para a linguagem de programação Erlang) https://github.com/SpaceTime-IoT/pgo . A mensagem de erro que recebo (quando passo "2 days"
ou "'2 days'"
como parâmetro de consulta) se parece com:
{error,{pgsql_error,#{code => <<"08P01">>,file => <<"pqformat.c">>,
line => <<"575">>,
message => <<"insufficient data left in message">>,
routine => <<"pq_copymsgbytes">>,severity => <<"ERROR">>,
{unknown,86} => <<"ERROR">>}}}
E quando passo '2 days'
como parâmetro, dá um badarg
erro.
TLDR: Pule para o capítulo "Consulta superior" abaixo.
Você não divulgou o módulo com o qual está trabalhando, mas o problema é obviamente de conversão de tipo . Parece que seu parâmetro é passado como valor digitado e presumo
text
ouvarchar
. Não há conversão de tipo implícita paratext
->interval
:db<>fique aqui
Se minhas suposições estiverem corretas, você deverá ver uma mensagem de erro como:
Estou bastante confiante de que seu módulo não divulgado tem maneiras de passar um tipo de dados diferente ou um literal de string não tipado. O Postgres oferece essa funcionalidade.
Você também afirma:
Isso é estranho, porque uma conversão de tipo explícito também deve funcionar.
Demonstração
LINHA 2: ... current_timestamp - timestamp '2018-05-04 18:40' < text '6 ... ^ DICA: Nenhum operador corresponde ao nome e tipo de argumento fornecidos. Talvez seja necessário adicionar conversões de tipo explícitas.
O mesmo vale para declarações preparadas:
LINHA 3: ...ELECT current_timestamp - timestamp '2018-05-04 18:40' < $1; ^ DICA: Nenhum operador corresponde ao nome e tipo de argumento fornecidos. Talvez seja necessário adicionar conversões de tipo explícitas.
db<>fique aqui
Consulta superior
Tudo isso de lado, nenhuma de suas consultas pode usar um índice (não "sargable"). Use algo assim em vez disso!
Você pode multiplicar um
interval
cominteger
.Ou se você descobrir o problema com a passagem de parâmetros digitados:
Usando
localtimestamp
para apontar que o "horário atual" depende da configuração do fuso horário atual com o tipotimestamp
. Detalhes:Eu descobri uma solução alternativa para atingir o mesmo objetivo.
A abordagem aproveita o fato de que a diferença de duas datas é um número inteiro; é simples converter um carimbo de data/hora em uma data e valores inteiros podem ser usados em consultas parametrizadas do servidor para o banco de dados.