Ten artykuł jest obecnie po rosyjsku — trwa tłumaczenie na angielski.
POWER(base, exponent) возводит число в степень: POWER(2, 10) равно 1024. Эта функция нужна там, где аналитическому запросу перестаёт хватать сложения и умножения — спрогнозировать сложный рост выручки, сжать длинный хвост сумм заказов кубическим корнем или извлечь корень любой степени через дробный показатель. Вся арифметика роста, нормализации метрик и корней держится на этом одном вызове.
Базовый синтаксис
POWER принимает два аргумента — основание и показатель степени — и возвращает число с плавающей точкой (в PostgreSQL это double precision). Псевдоним POW работает в MySQL и ClickHouse; в PostgreSQL живут оба имени, так что переносить запросы между ними проще.
SELECT POWER(2, 10) AS kib,
POWER(10, 6) AS million,
POWER(2, -1) AS half;
Отрицательный показатель даёт дробь, нулевой — всегда единицу. В PostgreSQL под рукой ещё и инфиксный оператор ^, который читается в формулах естественнее вызова функции:
SELECT 2 ^ 10 AS via_operator;
- В MySQL и ClickHouse
^ — это побитовый XOR, а вовсе не степень. Там берите POW, иначе получите молча неверный результат вместо ошибки.
- Результат всегда вещественный; за целым числом оборачивайте вызов в
ROUND(...)::bigint.
Дробные показатели и корни
Корень n-й степени — это та же степень, только показатель равен 1/n. У квадратного корня есть собственная функция SQRT, но POWER берёт корень любой степени, а не только второй.
SELECT POWER(27, 1.0 / 3) AS cube_root,
POWER(16, 0.25) AS fourth_root,
SQRT(2) AS sqrt2;
Самое наглядное применение — сгладить разброс сумм заказов кубическим корнем. Это ходовой приём для дашбордов: он притягивает выбросы к остальной массе, и одна гигантская сделка перестаёт перетягивать на себя всю шкалу.
SELECT id,
amount,
ROUND(POWER(amount, 1.0 / 3), 2) AS dampened
FROM orders
WHERE status = 'paid'
ORDER BY amount DESC;
Геометрическое среднее зарплат по отделу — ещё один сюжет, где обычно блистают EXP и LN, но корень тоже выражается через POWER. На практике для произведения многих чисел берут именно логарифмический трюк — он устойчивее к переполнению:
SELECT dept,
ROUND(EXP(AVG(LN(salary))), 2) AS geo_mean_salary
FROM employees
GROUP BY dept;
- Пишите
1.0 / 3, а не 1 / 3. В PostgreSQL и MySQL целочисленное деление 1 / 3 обнулится в 0, показатель схлопнется, и любое основание превратится в 1. Грабли тихие: ошибки нет, просто весь столбец оказывается единицами.
Сложный процент и рост
Классическая формула сложного роста — base * (1 + rate) ^ periods. Прикинем, во что превратится средний чек, если он год подряд прибавляет по 3% в месяц:
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';
Обратная задача — найти средний месячный темп (CAGR) — тоже опирается на POWER, но с дробным показателем: мы извлекаем корень из накопленного множителя. Важно честно прочитать запрос ниже: он берёт корень 12-й степени из общего числа регистраций total, поэтому first_day и last_day здесь служат только подписями периода и в расчёт не входят. Это грубая прикидка «множителя за 12 шагов», а не строгий CAGR по отношению последнего значения к первому. Для настоящего CAGR множителем должно быть отношение last/first (например, last_count / first_count), показателем — единица, делённая на число периодов, то есть POWER(last_count / first_count, 1.0 / 12) - 1. Поэтому раскрытое выше выражение POWER(total, 1.0 / 12) стоит понимать как нормализацию объёма, а не как темп; прежде чем выносить такую колонку в витрину, замените total на корректное отношение граничных значений:
WITH bounds AS (
SELECT MIN(created_at) AS first_day,
MAX(created_at) AS last_day,
COUNT(*) AS total
FROM users
)
SELECT ROUND(
(POWER(total, 1.0 / 12) - 1) * 100, 2
) AS approx_monthly_growth_pct
FROM bounds;
Переполнение и подводные камни
Степени растут не линейно, а взрывообразно: каждый шаг показателя умножает результат заново, поэтому даже скромное основание мгновенно упирается в потолок типа. Большой показатель легко выскакивает за пределы double precision, и тогда PostgreSQL бросает value out of range: overflow вместо тихого NULL. Это, как ни странно, удобно — переполнение нельзя проглядеть, — но запрос приходится подстраховывать заранее: ограничивать диапазон показателя или переводить данные в numeric.
SELECT POWER(10, 308);
SELECT POWER(10, 309);
- Отрицательное основание с дробным показателем (
POWER(-8, 0.5)) — это комплексное число; PostgreSQL вернёт ошибку, а не NaN.
- В PostgreSQL
POWER(numeric, numeric) точнее, но дороже версии для double precision. Для денег приводите к numeric осознанно, а не на всякий случай.
- В ClickHouse
pow всегда отдаёт Float64, так что на больших значениях ждите ошибок округления.
POWER(0, 0) равно 1 во всех трёх СУБД — это математическое соглашение, а не баг.
Держите показатели в разумных пределах, приводите типы явно и пишите 1.0 / n для корней — и POWER останется предсказуемым инструментом и для аналитики, и для финансовых формул.
POWER(base, exponent)возводит число в степень:POWER(2, 10)равно1024. Эта функция нужна там, где аналитическому запросу перестаёт хватать сложения и умножения — спрогнозировать сложный рост выручки, сжать длинный хвост сумм заказов кубическим корнем или извлечь корень любой степени через дробный показатель. Вся арифметика роста, нормализации метрик и корней держится на этом одном вызове.Базовый синтаксис
POWERпринимает два аргумента — основание и показатель степени — и возвращает число с плавающей точкой (в PostgreSQL этоdouble precision). ПсевдонимPOWработает в MySQL и ClickHouse; в PostgreSQL живут оба имени, так что переносить запросы между ними проще.SELECT POWER(2, 10) AS kib, -- 1024 POWER(10, 6) AS million, -- 1000000 POWER(2, -1) AS half; -- 0.5Отрицательный показатель даёт дробь, нулевой — всегда единицу. В PostgreSQL под рукой ещё и инфиксный оператор
^, который читается в формулах естественнее вызова функции:SELECT 2 ^ 10 AS via_operator; -- 1024 in PostgreSQL^— это побитовый XOR, а вовсе не степень. Там беритеPOW, иначе получите молча неверный результат вместо ошибки.ROUND(...)::bigint.Дробные показатели и корни
Корень n-й степени — это та же степень, только показатель равен
1/n. У квадратного корня есть собственная функцияSQRT, ноPOWERберёт корень любой степени, а не только второй.SELECT POWER(27, 1.0 / 3) AS cube_root, -- 3 POWER(16, 0.25) AS fourth_root, -- 2 SQRT(2) AS sqrt2; -- 1.4142...Самое наглядное применение — сгладить разброс сумм заказов кубическим корнем. Это ходовой приём для дашбордов: он притягивает выбросы к остальной массе, и одна гигантская сделка перестаёт перетягивать на себя всю шкалу.
SELECT id, amount, ROUND(POWER(amount, 1.0 / 3), 2) AS dampened FROM orders WHERE status = 'paid' ORDER BY amount DESC;Геометрическое среднее зарплат по отделу — ещё один сюжет, где обычно блистают
EXPиLN, но корень тоже выражается черезPOWER. На практике для произведения многих чисел берут именно логарифмический трюк — он устойчивее к переполнению:SELECT dept, ROUND(EXP(AVG(LN(salary))), 2) AS geo_mean_salary FROM employees GROUP BY dept;1.0 / 3, а не1 / 3. В PostgreSQL и MySQL целочисленное деление1 / 3обнулится в0, показатель схлопнется, и любое основание превратится в1. Грабли тихие: ошибки нет, просто весь столбец оказывается единицами.Сложный процент и рост
Классическая формула сложного роста —
base * (1 + rate) ^ periods. Прикинем, во что превратится средний чек, если он год подряд прибавляет по 3% в месяц: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';Обратная задача — найти средний месячный темп (CAGR) — тоже опирается на
POWER, но с дробным показателем: мы извлекаем корень из накопленного множителя. Важно честно прочитать запрос ниже: он берёт корень 12-й степени из общего числа регистрацийtotal, поэтомуfirst_dayиlast_dayздесь служат только подписями периода и в расчёт не входят. Это грубая прикидка «множителя за 12 шагов», а не строгий CAGR по отношению последнего значения к первому. Для настоящего CAGR множителем должно быть отношение last/first (например,last_count / first_count), показателем — единица, делённая на число периодов, то естьPOWER(last_count / first_count, 1.0 / 12) - 1. Поэтому раскрытое выше выражениеPOWER(total, 1.0 / 12)стоит понимать как нормализацию объёма, а не как темп; прежде чем выносить такую колонку в витрину, заменитеtotalна корректное отношение граничных значений:WITH bounds AS ( SELECT MIN(created_at) AS first_day, MAX(created_at) AS last_day, COUNT(*) AS total FROM users ) SELECT ROUND( (POWER(total, 1.0 / 12) - 1) * 100, 2 ) AS approx_monthly_growth_pct FROM bounds;Переполнение и подводные камни
Степени растут не линейно, а взрывообразно: каждый шаг показателя умножает результат заново, поэтому даже скромное основание мгновенно упирается в потолок типа. Большой показатель легко выскакивает за пределы
double precision, и тогда PostgreSQL бросаетvalue out of range: overflowвместо тихогоNULL. Это, как ни странно, удобно — переполнение нельзя проглядеть, — но запрос приходится подстраховывать заранее: ограничивать диапазон показателя или переводить данные вnumeric.SELECT POWER(10, 308); -- ok, near the double precision limit SELECT POWER(10, 309); -- ERROR: value out of range: overflowPOWER(-8, 0.5)) — это комплексное число; PostgreSQL вернёт ошибку, а неNaN.POWER(numeric, numeric)точнее, но дороже версии дляdouble precision. Для денег приводите кnumericосознанно, а не на всякий случай.powвсегда отдаётFloat64, так что на больших значениях ждите ошибок округления.POWER(0, 0)равно1во всех трёх СУБД — это математическое соглашение, а не баг.Держите показатели в разумных пределах, приводите типы явно и пишите
1.0 / nдля корней — иPOWERостанется предсказуемым инструментом и для аналитики, и для финансовых формул.