numeric
é exato!
Ao contrário do reivindicado por outra resposta,
numeric
não é um tipo de ponto flutuante , mas um tipo de precisão arbitrária conforme definido pelo padrão SQL. O armazenamento é exato . Cito o manual:
O tipo numeric pode armazenar números com um número muito grande de dígitos e realizar cálculos com exatidão. É especialmente recomendado para armazenar valores monetários e outras quantidades onde a exatidão é necessária.
Resposta
O candidato natural para sua pergunta é a função
trunc()
. Ele trunca em direção a zero - basicamente mantendo a parte inteira enquanto descarta o resto. Mais rápido em um teste rápido, mas a diferença é insignificante entre os principais concorrentes. SELECT * FROM t WHERE amount <> trunc(amount);
floor()
trunca para o próximo inteiro inferior, o que faz diferença com números negativos:SELECT * FROM t WHERE amount <> floor(amount);
Se seus números se encaixam em
integer
/ bigint
você também pode simplesmente lançar:SELECT * FROM t WHERE amount <> amount::bigint;
Esta rodadas para números completos, ao contrário do acima.
Teste
Testado com PostgreSQL 9.1.7. Tabela temporária com 10k
numeric
números com dois dígitos fracionários, cerca de 1% tem .00
. CREATE TEMP TABLE t(amount) AS
SELECT round((random() * generate_series (1,10000))::numeric, 2);
Resultado correto no meu caso:9890 linhas. Melhor tempo de 10 execuções com
EXPLAIN ANALYZE
. Erwin 1
SELECT count(*) FROM t WHERE amount <> trunc(amount) -- 43.129 ms
mvp 2 / qqx
SELECT count(*) FROM t WHERE amount != round(amount) -- 43.406 ms
Erwin 3
SELECT count(*) FROM t WHERE amount <> amount::int -- 43.668 ms
mvp 1
SELECT count(*) FROM t WHERE round(amount,2) != round(amount) -- 44.144 ms
Erwin 4
SELECT count(*) FROM t WHERE amount <> amount::bigint -- 44.149 ms
Erwin 2
SELECT count(*) FROM t WHERE amount <> floor(amount) -- 44.918 ms
Nandakumar V
SELECT count(*) FROM t WHERE amount - floor(amount) > .00 -- 46.640 ms
Principalmente ainda é verdade no Postgres 12 (exceto que tudo é> 10x mais rápido agora). Teste com 100 mil linhas em vez de 10 mil:
db<>mexa aqui