sqlpostgresqlmathpower

A funcao POWER no SQL: potencias, raizes e crescimento composto

Como usar POWER para potencias, raizes fracionarias e calculos de crescimento composto no PostgreSQL, MySQL e ClickHouse.

3 min de leituraReferencesql · postgresql · math · power · functions

POWER(base, expoente) eleva um numero a uma potencia: POWER(2, 10) e 1024. E a ferramenta de base para calculos de crescimento, normalizacao de metricas e extracao de raizes por meio de um expoente fracionario.

Sintaxe basica

POWER recebe dois argumentos — a base e o expoente — e retorna um numero de ponto flutuante (double precision no PostgreSQL). O alias POW funciona no MySQL e no ClickHouse; o PostgreSQL aceita os dois nomes.

SELECT POWER(2, 10) AS kib,      -- 1024
       POWER(10, 6) AS million,  -- 1000000
       POWER(2, -1) AS half;     -- 0.5

Um expoente negativo produz uma fracao, e um expoente zero sempre e um. O PostgreSQL tambem tem um operador infixo ^ que fica bem dentro de formulas:

SELECT 2 ^ 10 AS via_operator;   -- 1024 in PostgreSQL
  • No MySQL e no ClickHouse, ^ e um XOR bit a bit, nao uma potencia. La use POW.
  • O resultado e sempre real; para uma resposta inteira envolva em ROUND(...)::bigint.

Expoentes fracionarios e raizes

Uma raiz n-esima e apenas elevar um valor a potencia 1/n. A raiz quadrada tem a sua propria funcao, SQRT, mas POWER te da qualquer raiz.

SELECT POWER(27, 1.0 / 3) AS cube_root,    -- 3
       POWER(16, 0.25)     AS fourth_root,  -- 2
       SQRT(2)             AS sqrt2;        -- 1.4142...

Use isso para comprimir a dispersao dos valores de pedidos com uma raiz cubica, um truque comum para amortecer outliers em paineis:

SELECT id,
       amount,
       ROUND(POWER(amount, 1.0 / 3), 2) AS dampened
FROM orders
WHERE status = 'paid'
ORDER BY amount DESC;

A media geometrica dos salarios por departamento e outro caso em que EXP e LN brilham, mas uma raiz tambem pode ser expressa por POWER:

SELECT dept,
       ROUND(EXP(AVG(LN(salary))), 2) AS geo_mean_salary
FROM employees
GROUP BY dept;
  • Escreva 1.0 / 3, nao 1 / 3: no PostgreSQL e no MySQL a divisao inteira de 1 / 3 e 0, o que colapsa todo o resultado para 1.

Juros compostos e crescimento

A formula classica de capitalizacao e base * (1 + taxa) ^ periodos. Vamos projetar onde fica o valor medio do pedido se ele crescer 3% ao mes durante um ano inteiro.

SELECT ROUND(AVG(amount), 2)                          AS avg_now,
       ROUND(AVG(amount) * POWER(1 + 0.03, 12), 2)    AS avg_in_a_year
FROM orders
WHERE status = 'paid';

O problema inverso — encontrar a taxa media de crescimento mensal (CAGR) dos cadastros — tambem se apoia em POWER com um expoente fracionario. A base deve ser a razao entre o ultimo valor e o primeiro (last_count / first_count), e o expoente e um sobre o numero de periodos: POWER(last_count / first_count, 1.0 / periodos) - 1. Um simples COUNT(*) sobre todo o intervalo nao da essa razao: ele conta linhas, nao o crescimento delas do primeiro mes ao ultimo. Por isso pegamos os cadastros do primeiro e do ultimo mes separadamente e dividimos um pelo outro. Repare no 1.0 do expoente e na conversao para numeric, para que nenhuma divisao colapse para zero:

WITH monthly AS (
    SELECT date_trunc('month', created_at) AS m,
           COUNT(*)                        AS signups
    FROM users
    GROUP BY 1
),
bounds AS (
    SELECT (SELECT signups FROM monthly ORDER BY m ASC  LIMIT 1) AS first_count,
           (SELECT signups FROM monthly ORDER BY m DESC LIMIT 1) AS last_count,
           (SELECT COUNT(*) - 1 FROM monthly)                    AS periods
)
SELECT ROUND(
         (POWER(last_count::numeric / first_count, 1.0 / periods) - 1) * 100, 2
       ) AS monthly_growth_pct
FROM bounds;

Overflow e pegadinhas

As potencias crescem de forma explosiva. Um expoente grande estoura o tipo rapidamente, e o PostgreSQL lanca value out of range: overflow em vez de um NULL silencioso.

SELECT POWER(10, 308);   -- ok, near the double precision limit
SELECT POWER(10, 309);   -- ERROR: value out of range: overflow
  • Uma base negativa com expoente fracionario (POWER(-8, 0.5)) e um numero complexo; o PostgreSQL lanca um erro em vez de retornar NaN.
  • No PostgreSQL, POWER(numeric, numeric) e mais preciso, porem mais caro que a versao de double precision. Converta para numeric de forma deliberada quando lidar com dinheiro.
  • O pow do ClickHouse sempre retorna Float64, entao espere erro de arredondamento em magnitudes grandes.
  • POWER(0, 0) e 1 nos tres motores — uma convencao matematica, nao um bug.

Mantenha os expoentes dentro de limites razoaveis, converta os tipos de forma explicita e use 1.0 / n para as raizes; assim POWER continua sendo uma ferramenta previsivel tanto para analise quanto para formulas financeiras.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador