Литералы, выражения и вычисляемые колонки
Литералы, выражения и вычисляемые колонки
До этого момента в SELECT-списке мы писали только имена колонок. Но SQL позволяет значительно больше: вычислять арифметические выражения, строить строки, подставлять константы и даже комбинировать всё это прямо в запросе. В этом уроке разберём литералы — «жёсткие» значения прямо в коде, и выражения — вычисления над данными из таблицы.
Что такое литерал
Литерал — это фиксированное значение, записанное непосредственно в запросе. Он не берётся из таблицы; он всегда возвращает одно и то же.
Примеры литералов разных типов:
SELECT 42; -- числовой литерал
SELECT 3.14; -- дробный литерал
SELECT 'Привет, мир'; -- строковый литерал (в одинарных кавычках)
SELECT TRUE; -- логический литерал
SELECT NULL; -- специальное значение «ничего»
Строковые литералы всегда в одинарных кавычках. Двойные кавычки в SQL — для имён объектов (таблиц, колонок). Путать их — типичная ошибка.
Литералы можно добавлять как «колонки» в SELECT:
SELECT name, 'активен' AS статус
FROM employees;
Результат: для каждой строки в колонке статус будет стоять строка 'активен'. Это может показаться бесполезным, но иногда нужно добавить константу к результату — например, метку источника данных или фиксированное значение по умолчанию.
Арифметические выражения
В SELECT-списке можно использовать арифметику над числовыми колонками. Все базовые операторы работают стандартно:
| Оператор | Смысл | Пример |
|---|---|---|
+ | сложение | price + 100 |
- | вычитание | price - discount |
* | умножение | price * quantity |
/ | деление | total / count |
% | остаток от деления | id % 2 |
Пример — таблица order_items (позиции заказа):
SELECT product_name,
quantity,
unit_price,
quantity * unit_price AS total_price
FROM order_items;
Результат:
product_name | quantity | unit_price | total_price
-------------+----------+------------+------------
Ноутбук | 2 | 55000 | 110000
Мышь | 5 | 1200 | 6000
Монитор | 1 | 28000 | 28000
Колонка total_price — вычисляемая. Её нет в таблице; СУБД считает её на лету для каждой строки. Псевдоним AS total_price даёт ей понятное имя.
Проверь себя: что вернёт выражение price * 1.2 AS price_with_vat для price = 1000?
Целочисленное деление и дроби
Важная деталь: в PostgreSQL деление целых чисел даёт целое число. Остаток отбрасывается:
SELECT 7 / 2; -- результат: 3, не 3.5
SELECT 7.0 / 2; -- результат: 3.5
Если нужен дробный результат, хотя бы один из операндов должен быть дробным числом. Часто используют явное приведение типа:
SELECT total::DECIMAL / count AS average
FROM statistics;
:: — оператор приведения типа в PostgreSQL. DECIMAL означает дробное число. Детали типов данных будем разбирать подробнее в модуле 9.
Строковые выражения: конкатенация
Строки в SQL объединяются оператором || (двойная вертикальная черта):
SELECT first_name || ' ' || last_name AS full_name
FROM employees;
Результат:
full_name
-----------
Анна Иванова
Борис Петров
Вера Сидорова
Оператор || берёт строки и «склеивает» их. В примере выше между именем и фамилией добавлена строка ' ' (пробел) — иначе имена бы слиплись: АннаИванова.
PostgreSQL также предоставляет функцию CONCAT(), которая делает то же самое, но чуть иначе обрабатывает NULL:
SELECT CONCAT(first_name, ' ', last_name) AS full_name
FROM employees;
CONCAT() игнорирует NULL-аргументы; || вернёт NULL, если любой из операндов — NULL. Это важная разница, которую стоит держать в голове.
Проверь себя: что вернёт 'Иван' || NULL || 'ов' в PostgreSQL?
Функции в выражениях
SQL поддерживает множество встроенных функций, которые можно использовать прямо в SELECT. Несколько полезных примеров:
SELECT name,
UPPER(name) AS name_upper, -- все буквы заглавные
LOWER(name) AS name_lower, -- все буквы строчные
LENGTH(name) AS name_length -- длина строки
FROM products;
Функции для чисел:
SELECT price,
ROUND(price * 0.13, 2) AS tax, -- округление до 2 знаков
ABS(balance) AS abs_balance -- модуль числа
FROM finance;
Функции работают так же, как в любом языке программирования: принимают аргументы, возвращают результат. Полный список встроенных функций PostgreSQL огромен — заглядывайте в документацию по мере необходимости.
Выражения с датами
С датами тоже можно делать вычисления. PostgreSQL поддерживает арифметику над датами:
SELECT name,
hire_date,
CURRENT_DATE - hire_date AS days_employed
FROM employees;
CURRENT_DATE — встроенная функция, возвращающая сегодняшнюю дату. Разность двух дат даёт количество дней. Работа с датами — обширная тема, которая будет в разделе типов данных.
Выражения без таблицы
Как мы уже видели в уроке про синтаксис SELECT, PostgreSQL позволяет использовать SELECT без FROM:
SELECT 10 + 5; -- 15
SELECT 'SQL' || ' OK'; -- SQL OK
SELECT UPPER('hello'); -- HELLO
SELECT CURRENT_DATE; -- сегодняшняя дата
Это удобно для быстрой проверки выражений в консоли — своего рода «калькулятор» прямо в psql.
Приоритет операторов
Арифметические операторы следуют стандартным математическим правилам приоритета: * и / выполняются до + и -. Скобки меняют порядок:
SELECT price + discount * 2; -- discount * 2, затем + price
SELECT (price + discount) * 2; -- сначала сложение, потом умножение
Когда не уверены в приоритете — ставьте скобки. Явность лучше неожиданного результата.
Типичные ошибки с литералами
1. Двойные кавычки вместо одинарных для строк:
SELECT "Привет" AS message; -- ошибка: PostgreSQL ищет колонку с именем "Привет"
SELECT 'Привет' AS message; -- правильно: строковый литерал
2. Деление целых чисел:
SELECT 1 / 3; -- результат: 0, не 0.333...
SELECT 1.0 / 3; -- результат: 0.3333...
3. NULL в арифметике:
SELECT 5 + NULL; -- результат: NULL
SELECT 5 * NULL; -- результат: NULL
Любая арифметическая операция с NULL возвращает NULL. Это «вирусное» поведение NULL — одна из особенностей SQL, которую важно знать.
Практический пример: прайс-лист с расчётами
Соберём всё вместе:
SELECT name AS "Товар",
price AS "Цена",
price * 0.9 AS "Цена со скидкой 10%",
ROUND(price * 0.13, 2) AS "НДС",
'руб.' AS "Валюта"
FROM products;
Этот запрос возвращает таблицу с пятью колонками — три вычислены на лету, одна взята из таблицы, одна — константа. Всё это без изменения исходных данных.
Когда выражения особенно полезны
Вот несколько реальных сценариев, где вычисляемые колонки незаменимы:
Отчёты и аналитика. Вместо того чтобы вытягивать «сырые» данные и считать в Python или Excel, можно вычислить прямо в SQL:
SELECT year,
revenue,
costs,
revenue - costs AS profit,
(revenue - costs) * 100.0 / revenue AS profit_margin_percent
FROM annual_stats;
Форматирование данных. Собрать полное имя из частей, добавить единицы измерения:
SELECT last_name || ', ' || first_name AS "ФИО",
salary || ' руб.' AS "Зарплата"
FROM employees;
Нормализация значений. Перевести единицы на лету:
SELECT product_name,
weight_grams AS "Вес (г)",
weight_grams / 1000.0 AS "Вес (кг)"
FROM products;
Все эти вычисления выполняются на стороне сервера БД, без загрузки данных в приложение. Это эффективно и удобно.
Выражения и DISTINCT
Вычисляемые колонки хорошо работают вместе с DISTINCT, который вы изучили в предыдущем уроке:
SELECT DISTINCT UPPER(category) AS category_upper
FROM products;
Сначала для каждой строки применяется функция UPPER(), затем DISTINCT убирает дубликаты. Порядок логический: сначала вычисления, потом дедупликация.
Краткий итог
- Литерал — фиксированное значение прямо в запросе: числа, строки в
'кавычках',TRUE/FALSE,NULL - Арифметика:
+,-,*,/,%; деление целых даёт целое - Конкатенация строк:
||;CONCAT()— альтернатива с другим поведением дляNULL - Встроенные функции (
UPPER,LENGTH,ROUND) работают прямо вSELECT - Любая операция с
NULLвозвращаетNULL - Строковые литералы — одинарные кавычки; двойные — для имён объектов
Что дальше
Вы освоили вычисления прямо в SELECT. Финальный урок этого модуля посвящён оформлению запросов: комментарии, форматирование, читаемость кода. Это не «синтаксис», но хорошие привычки с самого начала сэкономят много времени.