SQRT — это функция, которая извлекает квадратный корень из числа.
Например:
SELECT SQRT(144);
Результат:
12
А так можно получить корень из двойки:
SELECT SQRT(2);
Результат будет приблизительным:
1.4142135623730951
На первый взгляд функция совсем простая: передали число — получили корень. Но в реальных запросах у SQRT быстро появляются важные нюансы.
Она нужна не только в школьной математике. В SQL квадратный корень часто встречается в аналитике, геометрии и статистике:
- посчитать расстояние между двумя точками;
- найти длину вектора;
- посчитать стандартное отклонение вручную;
- нормализовать значения;
- измерить «разброс» данных.
Именно поэтому важно понимать не только синтаксис, но и поведение функции на плохих данных.
Базовый синтаксис SQRT
Синтаксис очень простой:
SQRT(number)
Функция принимает число и возвращает его квадратный корень.
SELECT
SQRT(144) AS root_144,
SQRT(25) AS root_25,
SQRT(2) AS root_2;
Результат будет примерно таким:
root_144 | root_25 | root_2
---------+---------+-------------------
12 | 5 | 1.4142135623730951
Квадратный корень — это число, которое при умножении само на себя даёт исходное значение.
Например:
12 * 12 = 144
5 * 5 = 25
Поэтому SQRT(144) возвращает 12, а SQRT(25) возвращает 5.
Где SQRT встречается в SQL
В обычных бизнес-запросах SQRT нужна не каждый день. Но как только начинается аналитика, функция становится очень полезной.
Например, расстояние между двумя точками считается через корень:
distance = sqrt(dx * dx + dy * dy)
Стандартное отклонение тоже связано с квадратным корнем:
stddev = sqrt(variance)
То есть SQRT часто появляется там, где мы сначала считаем сумму квадратов, а потом хотим вернуться к обычной шкале измерения.
Если зарплаты измеряются в рублях, дисперсия будет в «рублях в квадрате». Это неудобно для чтения. Квадратный корень возвращает результат обратно в рубли.
Типы: numeric и double precision
В PostgreSQL SQRT может работать с разными числовыми типами.
Если передать обычное число с плавающей точкой, результат будет типа double precision.
SELECT pg_typeof(SQRT(2::double precision)) AS result_type;
Результат:
double precision
Если передать numeric, PostgreSQL использует вариант функции для numeric, и результат тоже будет numeric.
SELECT pg_typeof(SQRT(2::numeric)) AS result_type;
Результат:
numeric
Разница важна.
numeric хранит числа точнее, особенно когда речь идёт о деньгах и аккуратных расчётах.
double precision работает быстрее, но хранит число приближённо. Это нормально для геометрии, статистики, расстояний и тяжёлой аналитики, где не нужны десятки точных знаков после запятой.
Когда выбирать numeric
Используйте numeric, если важна точность.
Например, если сумма заказа хранится как numeric, корень из неё тоже останется numeric.
SELECT
amount,
SQRT(amount) AS amount_root
FROM orders
WHERE status = 'paid';
Для денег обычно используют numeric, потому что финансовые значения не любят погрешности.
Да, SQRT(amount) в таком случае может быть медленнее, чем расчёт в double precision, но зато результат будет аккуратнее.
Когда выбирать double precision
Используйте double precision, если важна скорость и допустима небольшая погрешность.
Например, при расчёте расстояний на большом количестве строк.
SELECT
id,
SQRT(
power((x - 10)::double precision, 2)
+ power((y - 20)::double precision, 2)
) AS distance
FROM points;
Для миллионов строк это может быть заметно быстрее, чем расчёты в numeric.
Практическое правило простое:
- деньги и точные отчёты — чаще
numeric;
- геометрия, аналитика, статистика на больших данных — чаще
double precision.
SQRT и отрицательные числа
Квадратный корень из отрицательного числа в обычной вещественной математике не определён.
В PostgreSQL такой запрос приведёт к ошибке:
SELECT SQRT(-1);
Результат:
ERROR: cannot take square root of a negative number
Это важный момент.
PostgreSQL не вернёт NULL, не подставит ноль и не сделает вид, что всё хорошо. Он остановит запрос.
В учебном примере это выглядит безобидно. Но в реальной таблице одна плохая строка может уронить весь отчёт.
SELECT
id,
SQRT(value) AS root_value
FROM metrics;
Если хотя бы в одной строке value будет отрицательным, запрос завершится ошибкой.
Почему отрицательное значение может появиться неожиданно
Иногда мы передаём в SQRT не готовую колонку, а выражение.
Например:
SELECT
id,
SQRT(amount - refund_amount) AS net_root
FROM orders;
Кажется, что amount должен быть больше refund_amount. Но в данных могут быть возвраты, корректировки, ошибки импорта или нестандартные кейсы.
Если выражение amount - refund_amount станет отрицательным, SQRT упадёт.
Поэтому перед корнем нужно подумать:
Может ли внутри оказаться минус?
Если да — нужно явно решить, что с ним делать.
Как защититься через ABS
Если знак не важен, можно взять модуль через ABS.
SELECT
id,
SQRT(ABS(amount - refund_amount)) AS magnitude
FROM orders;
ABS превращает отрицательное число в положительное.
ABS(-25) = 25
ABS(25) = 25
Такой вариант подходит, когда вы измеряете величину отклонения, а направление храните отдельно.
Например:
SELECT
id,
SQRT(ABS(amount - 100)) AS magnitude,
SIGN(amount - 100) AS direction
FROM orders;
Здесь:
magnitude показывает размер отклонения;
direction показывает направление: значение выше или ниже базовой точки.
Как защититься через GREATEST
Иногда отрицательное значение появляется из-за маленькой погрешности округления.
Например, математически выражение должно быть равно нулю, но из-за вычислений в double precision получается что-то вроде -0.00000000001.
В таком случае удобно использовать GREATEST.
SELECT
SQRT(GREATEST(value, 0)) AS safe_root
FROM metrics;
GREATEST(value, 0) выбирает большее из двух значений.
Если value положительное, оно останется как есть.
Если value отрицательное, вместо него будет 0.
GREATEST(25, 0) = 25
GREATEST(-3, 0) = 0
Это полезная защита в статистических формулах, где маленький минус может появиться не из-за смысла данных, а из-за погрешности вычислений.
NULL не вызывает ошибку
Отрицательное число вызывает ошибку, а вот NULL ведёт себя спокойно.
SELECT SQRT(NULL);
Результат:
NULL
Это обычное поведение SQL-функций: если вход неизвестен, результат тоже неизвестен.
Например:
SELECT
id,
SQRT(value) AS root_value
FROM metrics;
Если value равен NULL, то root_value тоже будет NULL. Запрос не упадёт.
Но если value равен -1, запрос завершится ошибкой.
Это разные ситуации:
NULL — значения нет;
- отрицательное число — значение есть, но для квадратного корня оно недопустимо.
Евклидово расстояние между точками
Самое классическое применение SQRT — расстояние между двумя точками.
Представим координатную плоскость. Есть точка пользователя и точка офиса. Нужно понять, насколько пользователь далеко.
Расстояние считается по теореме Пифагора:
distance = sqrt(dx * dx + dy * dy)
Где:
dx — разница по первой координате;
dy — разница по второй координате.
Допустим, в таблице users есть координаты lat и lon.
Найдём расстояние до условной точки с координатами 40.0 и -3.7.
SELECT
id,
name,
SQRT(
power(lat - 40.0, 2)
+ power(lon - (-3.7), 2)
) AS dist
FROM users
ORDER BY dist
LIMIT 10;
Что происходит:
power(lat - 40.0, 2)
считает квадрат разницы по первой координате.
power(lon - (-3.7), 2)
считает квадрат разницы по второй координате.
Потом мы складываем эти квадраты и берём корень.
Так получаем расстояние.
Для учебной геометрии и простых задач этого достаточно. Для настоящих расстояний на Земле обычно нужны более сложные формулы, потому что Земля не плоская.
Когда SQRT можно не вызывать
Есть интересный приём: если вам нужно только отсортировать точки по близости, квадратный корень можно не считать.
Почему?
Потому что квадратный корень сохраняет порядок для неотрицательных чисел.
Если одно расстояние в квадрате меньше другого, то и само расстояние тоже меньше.
Например:
9 < 16
sqrt(9) < sqrt(16)
3 < 4
Поэтому вместо такого запроса:
SELECT
id,
name,
SQRT(
power(lat - 40.0, 2)
+ power(lon - (-3.7), 2)
) AS dist
FROM users
ORDER BY dist
LIMIT 10;
можно написать так:
SELECT
id,
name
FROM users
ORDER BY
power(lat - 40.0, 2)
+ power(lon - (-3.7), 2)
LIMIT 10;
Результат по порядку будет тем же: ближайшие пользователи останутся ближайшими.
Но база не будет считать SQRT для каждой строки.
Если таблица маленькая, разницу можно не заметить. А на миллионах строк лишний корень в сортировке уже может стоить времени.
Правило:
Если нужно само расстояние — считайте SQRT. Если нужен только порядок — можно сортировать по квадрату расстояния.
power или оператор ^
В PostgreSQL степень можно записать через power.
SELECT power(5, 2) AS square;
Результат:
25
Также есть оператор ^.
SELECT 5 ^ 2 AS square;
Но для начинающих и для читаемости чаще лучше использовать power.
power(x, 2)
Так сразу видно: мы возводим значение в степень.
К тому же в некоторых языках программирования символ ^ означает не степень, а побитовое исключающее ИЛИ. Из-за этого он может путать людей, которые пришли в SQL из Python, JavaScript или Java.
Стандартное отклонение и SQRT
Ещё одно важное применение SQRT — стандартное отклонение.
Стандартное отклонение показывает, насколько сильно значения разбросаны вокруг среднего.
Например, в одном отделе зарплаты почти одинаковые:
100000, 102000, 98000
В другом отделе разброс большой:
50000, 120000, 250000
Среднее значение может быть похожим, но разброс совершенно разный. Стандартное отклонение помогает это увидеть.
В PostgreSQL уже есть готовые функции:
stddev_pop(value)
stddev_samp(value)
В реальных задачах лучше использовать их.
Но один раз полезно собрать формулу руками, чтобы понять, зачем там нужен квадратный корень.
Стандартное отклонение руками
Одна из формул для генерального стандартного отклонения выглядит так:
stddev = sqrt(avg(x * x) - avg(x) * avg(x))
Посчитаем разброс зарплат по отделам.
SELECT
dept,
SQRT(AVG(power(salary, 2)) - power(AVG(salary), 2)) AS std_pop_manual,
stddev_pop(salary) AS std_pop_check
FROM employees
GROUP BY dept;
Здесь:
AVG(power(salary, 2)) — среднее от квадратов зарплат;
power(AVG(salary), 2) — квадрат средней зарплаты;
- разность между ними — дисперсия;
SQRT превращает дисперсию в стандартное отклонение.
Колонки std_pop_manual и std_pop_check должны получиться очень близкими.
Но в боевом коде всё равно лучше писать так:
SELECT
dept,
stddev_pop(salary) AS salary_std
FROM employees
GROUP BY dept;
Готовая функция короче, понятнее и лучше выражает намерение.
Оконный пример со стандартным отклонением
Формулу со SQRT можно использовать и в оконных функциях.
Например, покажем каждому сотруднику зарплату и стандартное отклонение зарплат внутри его отдела.
SELECT
id,
dept,
salary,
SQRT(
AVG(power(salary, 2)) OVER w
- power(AVG(salary) OVER w, 2)
) AS dept_std
FROM employees
WINDOW w AS (PARTITION BY dept);
Здесь окно:
WINDOW w AS (PARTITION BY dept)
говорит:
Считай средние значения отдельно внутри каждого отдела.
В результате каждая строка сотрудника получит рядом показатель разброса зарплат по своему отделу.
Для обучения это отличный пример: видно, как агрегаты, окна и SQRT складываются в настоящую аналитическую формулу.
Погрешность double precision
При работе с double precision иногда возникают маленькие погрешности.
Например, математически дисперсия должна быть равна нулю. Но из-за округления в вычислениях может получиться не 0, а крошечное отрицательное число.
-0.00000000001
Если передать его в SQRT, запрос упадёт.
Поэтому в ручных статистических формулах часто добавляют защиту:
SELECT
dept,
SQRT(
GREATEST(
AVG(power(salary::double precision, 2))
- power(AVG(salary::double precision), 2),
0
)
) AS std_pop_manual
FROM employees
GROUP BY dept;
GREATEST(..., 0) не даёт случайному маленькому минусу попасть внутрь корня.
Это не значит, что нужно всегда замазывать плохие данные. Если минус настоящий и большой, лучше разобраться с причиной. Но для микроскопической погрешности округления такая защита уместна.
SQRT и агрегаты
SQRT часто используют вместе с агрегатами.
Например, можно посчитать длину вектора по сумме квадратов.
SELECT
user_id,
SQRT(SUM(power(score, 2))) AS vector_length
FROM user_scores
GROUP BY user_id;
Что делает запрос:
- Для каждого пользователя берёт его значения
score.
- Возводит каждое значение в квадрат.
- Складывает квадраты.
- Берёт квадратный корень.
Так получается длина вектора.
Подобные формулы часто встречаются в аналитике, рекомендациях и машинном обучении. Даже если вы пока не пишете ML-модели в SQL, полезно узнавать этот шаблон:
sqrt(sum(x * x))
SQRT в отчётах: пример с отклонением от плана
Представим, что есть таблица продаж. У каждой строки есть план и факт.
sales_plan
sales_fact
Хотим измерить размер отклонения без учёта знака.
SELECT
id,
sales_plan,
sales_fact,
SQRT(power(sales_fact - sales_plan, 2)) AS absolute_deviation
FROM sales;
Математически это то же самое, что модуль:
SELECT
id,
sales_plan,
sales_fact,
ABS(sales_fact - sales_plan) AS absolute_deviation
FROM sales;
Для простого отклонения лучше использовать ABS: он короче и понятнее.
Но пример полезен, потому что показывает идею:
sqrt(x * x) = abs(x)
А когда отклонений несколько, например по двум координатам или нескольким признакам, появляется уже сумма квадратов и настоящий смысл SQRT.
Когда SQRT использовать не надо
SQRT не стоит добавлять в запрос просто «для красоты».
Если вы сортируете по расстоянию и не выводите само расстояние, можно сортировать по квадрату расстояния.
Если вы считаете стандартное отклонение, в боевом коде лучше использовать встроенную функцию stddev_pop или stddev_samp.
Если вам нужен модуль одного числа, используйте ABS, а не SQRT(power(x, 2)).
Например, так лучше:
SELECT ABS(amount - 100) AS diff
FROM orders;
А так избыточно:
SELECT SQRT(power(amount - 100, 2)) AS diff
FROM orders;
SQRT нужен там, где действительно есть корень из суммы квадратов или другая математическая формула с квадратным корнем.
MySQL: отрицательный аргумент ведёт себя иначе
При переносе запросов важно помнить: разные СУБД могут по-разному реагировать на плохой вход.
В MySQL корень из отрицательного числа может вернуть NULL.
SELECT SQRT(-1);
То есть запрос не обязательно упадёт так же жёстко, как в PostgreSQL.
С одной стороны, это кажется удобным. С другой — есть риск тихо получить NULL внутри отчёта и не заметить проблему сразу.
Например, если дальше результат участвует в агрегатах, пропущенные значения могут изменить итоговую картину.
Поэтому при переносе логики из PostgreSQL в MySQL проверяйте поведение на отрицательных значениях отдельно.
ClickHouse: возможен nan
В ClickHouse отрицательный аргумент для корня может дать специальное значение nan.
SELECT sqrt(-1);
nan означает «not a number», то есть «не число».
Опасность в том, что такое значение может пройти дальше по расчётам и испортить агрегаты или вывод.
PostgreSQL в этом смысле ведёт себя строже: он останавливает запрос ошибкой. Это неприятно в моменте, зато проблема становится видна сразу.
Как писать безопасные запросы с SQRT
Перед тем как использовать SQRT, полезно пройти короткую проверку.
Первый вопрос:
Может ли аргумент стать отрицательным?
Если да, выберите защиту.
Для величины без направления:
SELECT SQRT(ABS(value)) AS root_value
FROM metrics;
Для статистической формулы с возможной погрешностью:
SELECT SQRT(GREATEST(variance, 0)) AS stddev
FROM stats;
Второй вопрос:
Нужна ли точность numeric или хватит double precision?
Для точных денежных расчётов оставляйте numeric.
Для тяжёлой аналитики можно явно перейти к double precision.
SELECT SQRT(value::double precision) AS root_value
FROM metrics;
Третий вопрос:
Нужен ли сам корень или только порядок?
Если нужен только порядок, часто можно обойтись без SQRT.
SELECT
id,
name
FROM users
ORDER BY
power(lat - 40.0, 2)
+ power(lon - (-3.7), 2)
LIMIT 10;
Частые ошибки с SQRT
Первая ошибка — забыть про отрицательные значения.
SELECT SQRT(amount - refund_amount) AS root_value
FROM orders;
Если разность уйдёт в минус, запрос упадёт.
Вторая ошибка — использовать SQRT там, где достаточно ABS.
SELECT SQRT(power(amount - 100, 2)) AS diff
FROM orders;
Лучше так:
SELECT ABS(amount - 100) AS diff
FROM orders;
Третья ошибка — считать корень при сортировке, хотя нужен только порядок.
ORDER BY SQRT(power(x - 10, 2) + power(y - 20, 2))
Можно проще:
ORDER BY power(x - 10, 2) + power(y - 20, 2)
Четвёртая ошибка — вручную писать стандартное отклонение в продакшене, когда есть встроенная функция.
SELECT stddev_pop(salary) AS salary_std
FROM employees;
Пятая ошибка — не учитывать тип данных. numeric точнее, но медленнее. double precision быстрее, но приближённый.
Главное из статьи
SQRT в PostgreSQL извлекает квадратный корень из числа.
SELECT SQRT(144);
Результат:
12
Функция полезна в геометрии, статистике и аналитике: расстояния между точками, длины векторов, дисперсия и стандартное отклонение.
Главная опасность — отрицательный аргумент.
SELECT SQRT(-1);
В PostgreSQL такой запрос завершится ошибкой. Поэтому, если внутри корня может появиться минус, используйте ABS или GREATEST.
SELECT SQRT(ABS(value)) AS root_value
FROM metrics;
SELECT SQRT(GREATEST(variance, 0)) AS stddev
FROM stats;
Для точных расчётов используйте numeric, для быстрой аналитики чаще подходит double precision.
Если нужно только отсортировать точки по близости, сам корень можно не считать: порядок по квадрату расстояния будет тем же.
ORDER BY power(x - 10, 2) + power(y - 20, 2)
А если нужно стандартное отклонение, в реальном коде лучше брать встроенные функции PostgreSQL:
SELECT stddev_pop(value) AS stddev
FROM metrics;
SQRT — простая функция, но в рабочих запросах она требует дисциплины: проверяйте знак входного значения, осознанно выбирайте тип данных и не считайте корень там, где он не нужен.
SQRT— это функция, которая извлекает квадратный корень из числа.Например:
SELECT SQRT(144);Результат:
А так можно получить корень из двойки:
SELECT SQRT(2);Результат будет приблизительным:
На первый взгляд функция совсем простая: передали число — получили корень. Но в реальных запросах у
SQRTбыстро появляются важные нюансы.Она нужна не только в школьной математике. В SQL квадратный корень часто встречается в аналитике, геометрии и статистике:
Именно поэтому важно понимать не только синтаксис, но и поведение функции на плохих данных.
Базовый синтаксис SQRT
Синтаксис очень простой:
SQRT(number)Функция принимает число и возвращает его квадратный корень.
SELECT SQRT(144) AS root_144, SQRT(25) AS root_25, SQRT(2) AS root_2;Результат будет примерно таким:
Квадратный корень — это число, которое при умножении само на себя даёт исходное значение.
Например:
Поэтому
SQRT(144)возвращает12, аSQRT(25)возвращает5.Где SQRT встречается в SQL
В обычных бизнес-запросах
SQRTнужна не каждый день. Но как только начинается аналитика, функция становится очень полезной.Например, расстояние между двумя точками считается через корень:
Стандартное отклонение тоже связано с квадратным корнем:
То есть
SQRTчасто появляется там, где мы сначала считаем сумму квадратов, а потом хотим вернуться к обычной шкале измерения.Если зарплаты измеряются в рублях, дисперсия будет в «рублях в квадрате». Это неудобно для чтения. Квадратный корень возвращает результат обратно в рубли.
Типы: numeric и double precision
В PostgreSQL
SQRTможет работать с разными числовыми типами.Если передать обычное число с плавающей точкой, результат будет типа
double precision.SELECT pg_typeof(SQRT(2::double precision)) AS result_type;Результат:
Если передать
numeric, PostgreSQL использует вариант функции дляnumeric, и результат тоже будетnumeric.SELECT pg_typeof(SQRT(2::numeric)) AS result_type;Результат:
Разница важна.
numericхранит числа точнее, особенно когда речь идёт о деньгах и аккуратных расчётах.double precisionработает быстрее, но хранит число приближённо. Это нормально для геометрии, статистики, расстояний и тяжёлой аналитики, где не нужны десятки точных знаков после запятой.Когда выбирать numeric
Используйте
numeric, если важна точность.Например, если сумма заказа хранится как
numeric, корень из неё тоже останетсяnumeric.SELECT amount, SQRT(amount) AS amount_root FROM orders WHERE status = 'paid';Для денег обычно используют
numeric, потому что финансовые значения не любят погрешности.Да,
SQRT(amount)в таком случае может быть медленнее, чем расчёт вdouble precision, но зато результат будет аккуратнее.Когда выбирать double precision
Используйте
double precision, если важна скорость и допустима небольшая погрешность.Например, при расчёте расстояний на большом количестве строк.
SELECT id, SQRT( power((x - 10)::double precision, 2) + power((y - 20)::double precision, 2) ) AS distance FROM points;Для миллионов строк это может быть заметно быстрее, чем расчёты в
numeric.Практическое правило простое:
numeric;double precision.SQRT и отрицательные числа
Квадратный корень из отрицательного числа в обычной вещественной математике не определён.
В PostgreSQL такой запрос приведёт к ошибке:
SELECT SQRT(-1);Результат:
Это важный момент.
PostgreSQL не вернёт
NULL, не подставит ноль и не сделает вид, что всё хорошо. Он остановит запрос.В учебном примере это выглядит безобидно. Но в реальной таблице одна плохая строка может уронить весь отчёт.
SELECT id, SQRT(value) AS root_value FROM metrics;Если хотя бы в одной строке
valueбудет отрицательным, запрос завершится ошибкой.Почему отрицательное значение может появиться неожиданно
Иногда мы передаём в
SQRTне готовую колонку, а выражение.Например:
SELECT id, SQRT(amount - refund_amount) AS net_root FROM orders;Кажется, что
amountдолжен быть большеrefund_amount. Но в данных могут быть возвраты, корректировки, ошибки импорта или нестандартные кейсы.Если выражение
amount - refund_amountстанет отрицательным,SQRTупадёт.Поэтому перед корнем нужно подумать:
Если да — нужно явно решить, что с ним делать.
Как защититься через ABS
Если знак не важен, можно взять модуль через
ABS.SELECT id, SQRT(ABS(amount - refund_amount)) AS magnitude FROM orders;ABSпревращает отрицательное число в положительное.Такой вариант подходит, когда вы измеряете величину отклонения, а направление храните отдельно.
Например:
SELECT id, SQRT(ABS(amount - 100)) AS magnitude, SIGN(amount - 100) AS direction FROM orders;Здесь:
magnitudeпоказывает размер отклонения;directionпоказывает направление: значение выше или ниже базовой точки.Как защититься через GREATEST
Иногда отрицательное значение появляется из-за маленькой погрешности округления.
Например, математически выражение должно быть равно нулю, но из-за вычислений в
double precisionполучается что-то вроде-0.00000000001.В таком случае удобно использовать
GREATEST.SELECT SQRT(GREATEST(value, 0)) AS safe_root FROM metrics;GREATEST(value, 0)выбирает большее из двух значений.Если
valueположительное, оно останется как есть.Если
valueотрицательное, вместо него будет0.Это полезная защита в статистических формулах, где маленький минус может появиться не из-за смысла данных, а из-за погрешности вычислений.
NULL не вызывает ошибку
Отрицательное число вызывает ошибку, а вот
NULLведёт себя спокойно.SELECT SQRT(NULL);Результат:
Это обычное поведение SQL-функций: если вход неизвестен, результат тоже неизвестен.
Например:
SELECT id, SQRT(value) AS root_value FROM metrics;Если
valueравенNULL, тоroot_valueтоже будетNULL. Запрос не упадёт.Но если
valueравен-1, запрос завершится ошибкой.Это разные ситуации:
NULL— значения нет;Евклидово расстояние между точками
Самое классическое применение
SQRT— расстояние между двумя точками.Представим координатную плоскость. Есть точка пользователя и точка офиса. Нужно понять, насколько пользователь далеко.
Расстояние считается по теореме Пифагора:
Где:
dx— разница по первой координате;dy— разница по второй координате.Допустим, в таблице
usersесть координатыlatиlon.Найдём расстояние до условной точки с координатами
40.0и-3.7.SELECT id, name, SQRT( power(lat - 40.0, 2) + power(lon - (-3.7), 2) ) AS dist FROM users ORDER BY dist LIMIT 10;Что происходит:
power(lat - 40.0, 2)считает квадрат разницы по первой координате.
power(lon - (-3.7), 2)считает квадрат разницы по второй координате.
Потом мы складываем эти квадраты и берём корень.
Так получаем расстояние.
Для учебной геометрии и простых задач этого достаточно. Для настоящих расстояний на Земле обычно нужны более сложные формулы, потому что Земля не плоская.
Когда SQRT можно не вызывать
Есть интересный приём: если вам нужно только отсортировать точки по близости, квадратный корень можно не считать.
Почему?
Потому что квадратный корень сохраняет порядок для неотрицательных чисел.
Если одно расстояние в квадрате меньше другого, то и само расстояние тоже меньше.
Например:
Поэтому вместо такого запроса:
SELECT id, name, SQRT( power(lat - 40.0, 2) + power(lon - (-3.7), 2) ) AS dist FROM users ORDER BY dist LIMIT 10;можно написать так:
SELECT id, name FROM users ORDER BY power(lat - 40.0, 2) + power(lon - (-3.7), 2) LIMIT 10;Результат по порядку будет тем же: ближайшие пользователи останутся ближайшими.
Но база не будет считать
SQRTдля каждой строки.Если таблица маленькая, разницу можно не заметить. А на миллионах строк лишний корень в сортировке уже может стоить времени.
Правило:
power или оператор ^
В PostgreSQL степень можно записать через
power.SELECT power(5, 2) AS square;Результат:
Также есть оператор
^.SELECT 5 ^ 2 AS square;Но для начинающих и для читаемости чаще лучше использовать
power.power(x, 2)Так сразу видно: мы возводим значение в степень.
К тому же в некоторых языках программирования символ
^означает не степень, а побитовое исключающее ИЛИ. Из-за этого он может путать людей, которые пришли в SQL из Python, JavaScript или Java.Стандартное отклонение и SQRT
Ещё одно важное применение
SQRT— стандартное отклонение.Стандартное отклонение показывает, насколько сильно значения разбросаны вокруг среднего.
Например, в одном отделе зарплаты почти одинаковые:
В другом отделе разброс большой:
Среднее значение может быть похожим, но разброс совершенно разный. Стандартное отклонение помогает это увидеть.
В PostgreSQL уже есть готовые функции:
stddev_pop(value) stddev_samp(value)В реальных задачах лучше использовать их.
Но один раз полезно собрать формулу руками, чтобы понять, зачем там нужен квадратный корень.
Стандартное отклонение руками
Одна из формул для генерального стандартного отклонения выглядит так:
Посчитаем разброс зарплат по отделам.
SELECT dept, SQRT(AVG(power(salary, 2)) - power(AVG(salary), 2)) AS std_pop_manual, stddev_pop(salary) AS std_pop_check FROM employees GROUP BY dept;Здесь:
AVG(power(salary, 2))— среднее от квадратов зарплат;power(AVG(salary), 2)— квадрат средней зарплаты;SQRTпревращает дисперсию в стандартное отклонение.Колонки
std_pop_manualиstd_pop_checkдолжны получиться очень близкими.Но в боевом коде всё равно лучше писать так:
SELECT dept, stddev_pop(salary) AS salary_std FROM employees GROUP BY dept;Готовая функция короче, понятнее и лучше выражает намерение.
Оконный пример со стандартным отклонением
Формулу со
SQRTможно использовать и в оконных функциях.Например, покажем каждому сотруднику зарплату и стандартное отклонение зарплат внутри его отдела.
SELECT id, dept, salary, SQRT( AVG(power(salary, 2)) OVER w - power(AVG(salary) OVER w, 2) ) AS dept_std FROM employees WINDOW w AS (PARTITION BY dept);Здесь окно:
WINDOW w AS (PARTITION BY dept)говорит:
В результате каждая строка сотрудника получит рядом показатель разброса зарплат по своему отделу.
Для обучения это отличный пример: видно, как агрегаты, окна и
SQRTскладываются в настоящую аналитическую формулу.Погрешность double precision
При работе с
double precisionиногда возникают маленькие погрешности.Например, математически дисперсия должна быть равна нулю. Но из-за округления в вычислениях может получиться не
0, а крошечное отрицательное число.Если передать его в
SQRT, запрос упадёт.Поэтому в ручных статистических формулах часто добавляют защиту:
SELECT dept, SQRT( GREATEST( AVG(power(salary::double precision, 2)) - power(AVG(salary::double precision), 2), 0 ) ) AS std_pop_manual FROM employees GROUP BY dept;GREATEST(..., 0)не даёт случайному маленькому минусу попасть внутрь корня.Это не значит, что нужно всегда замазывать плохие данные. Если минус настоящий и большой, лучше разобраться с причиной. Но для микроскопической погрешности округления такая защита уместна.
SQRT и агрегаты
SQRTчасто используют вместе с агрегатами.Например, можно посчитать длину вектора по сумме квадратов.
SELECT user_id, SQRT(SUM(power(score, 2))) AS vector_length FROM user_scores GROUP BY user_id;Что делает запрос:
score.Так получается длина вектора.
Подобные формулы часто встречаются в аналитике, рекомендациях и машинном обучении. Даже если вы пока не пишете ML-модели в SQL, полезно узнавать этот шаблон:
SQRT в отчётах: пример с отклонением от плана
Представим, что есть таблица продаж. У каждой строки есть план и факт.
Хотим измерить размер отклонения без учёта знака.
SELECT id, sales_plan, sales_fact, SQRT(power(sales_fact - sales_plan, 2)) AS absolute_deviation FROM sales;Математически это то же самое, что модуль:
SELECT id, sales_plan, sales_fact, ABS(sales_fact - sales_plan) AS absolute_deviation FROM sales;Для простого отклонения лучше использовать
ABS: он короче и понятнее.Но пример полезен, потому что показывает идею:
А когда отклонений несколько, например по двум координатам или нескольким признакам, появляется уже сумма квадратов и настоящий смысл
SQRT.Когда SQRT использовать не надо
SQRTне стоит добавлять в запрос просто «для красоты».Если вы сортируете по расстоянию и не выводите само расстояние, можно сортировать по квадрату расстояния.
Если вы считаете стандартное отклонение, в боевом коде лучше использовать встроенную функцию
stddev_popилиstddev_samp.Если вам нужен модуль одного числа, используйте
ABS, а неSQRT(power(x, 2)).Например, так лучше:
SELECT ABS(amount - 100) AS diff FROM orders;А так избыточно:
SELECT SQRT(power(amount - 100, 2)) AS diff FROM orders;SQRTнужен там, где действительно есть корень из суммы квадратов или другая математическая формула с квадратным корнем.MySQL: отрицательный аргумент ведёт себя иначе
При переносе запросов важно помнить: разные СУБД могут по-разному реагировать на плохой вход.
В MySQL корень из отрицательного числа может вернуть
NULL.SELECT SQRT(-1);То есть запрос не обязательно упадёт так же жёстко, как в PostgreSQL.
С одной стороны, это кажется удобным. С другой — есть риск тихо получить
NULLвнутри отчёта и не заметить проблему сразу.Например, если дальше результат участвует в агрегатах, пропущенные значения могут изменить итоговую картину.
Поэтому при переносе логики из PostgreSQL в MySQL проверяйте поведение на отрицательных значениях отдельно.
ClickHouse: возможен nan
В ClickHouse отрицательный аргумент для корня может дать специальное значение
nan.SELECT sqrt(-1);nanозначает «not a number», то есть «не число».Опасность в том, что такое значение может пройти дальше по расчётам и испортить агрегаты или вывод.
PostgreSQL в этом смысле ведёт себя строже: он останавливает запрос ошибкой. Это неприятно в моменте, зато проблема становится видна сразу.
Как писать безопасные запросы с SQRT
Перед тем как использовать
SQRT, полезно пройти короткую проверку.Первый вопрос:
Если да, выберите защиту.
Для величины без направления:
SELECT SQRT(ABS(value)) AS root_value FROM metrics;Для статистической формулы с возможной погрешностью:
SELECT SQRT(GREATEST(variance, 0)) AS stddev FROM stats;Второй вопрос:
Для точных денежных расчётов оставляйте
numeric.Для тяжёлой аналитики можно явно перейти к
double precision.SELECT SQRT(value::double precision) AS root_value FROM metrics;Третий вопрос:
Если нужен только порядок, часто можно обойтись без
SQRT.SELECT id, name FROM users ORDER BY power(lat - 40.0, 2) + power(lon - (-3.7), 2) LIMIT 10;Частые ошибки с SQRT
Первая ошибка — забыть про отрицательные значения.
SELECT SQRT(amount - refund_amount) AS root_value FROM orders;Если разность уйдёт в минус, запрос упадёт.
Вторая ошибка — использовать
SQRTтам, где достаточноABS.SELECT SQRT(power(amount - 100, 2)) AS diff FROM orders;Лучше так:
SELECT ABS(amount - 100) AS diff FROM orders;Третья ошибка — считать корень при сортировке, хотя нужен только порядок.
ORDER BY SQRT(power(x - 10, 2) + power(y - 20, 2))Можно проще:
ORDER BY power(x - 10, 2) + power(y - 20, 2)Четвёртая ошибка — вручную писать стандартное отклонение в продакшене, когда есть встроенная функция.
SELECT stddev_pop(salary) AS salary_std FROM employees;Пятая ошибка — не учитывать тип данных.
numericточнее, но медленнее.double precisionбыстрее, но приближённый.Главное из статьи
SQRTв PostgreSQL извлекает квадратный корень из числа.SELECT SQRT(144);Результат:
Функция полезна в геометрии, статистике и аналитике: расстояния между точками, длины векторов, дисперсия и стандартное отклонение.
Главная опасность — отрицательный аргумент.
SELECT SQRT(-1);В PostgreSQL такой запрос завершится ошибкой. Поэтому, если внутри корня может появиться минус, используйте
ABSилиGREATEST.SELECT SQRT(ABS(value)) AS root_value FROM metrics;SELECT SQRT(GREATEST(variance, 0)) AS stddev FROM stats;Для точных расчётов используйте
numeric, для быстрой аналитики чаще подходитdouble precision.Если нужно только отсортировать точки по близости, сам корень можно не считать: порядок по квадрату расстояния будет тем же.
ORDER BY power(x - 10, 2) + power(y - 20, 2)А если нужно стандартное отклонение, в реальном коде лучше брать встроенные функции PostgreSQL:
SELECT stddev_pop(value) AS stddev FROM metrics;SQRT— простая функция, но в рабочих запросах она требует дисциплины: проверяйте знак входного значения, осознанно выбирайте тип данных и не считайте корень там, где он не нужен.