Даже опытные аналитики регулярно наступают на одни и те же грабли при написании SQL: путают порядок ключевых слов, забывают кавычки, неверно группируют условия в WHERE, ошибаются с форматами дат и типами данных. Большинство таких ошибок не связано с непониманием самой логики выборки — они возникают из-за невнимательности к синтаксису и деталям. Ниже разобраны типичные случаи с примерами «как не надо» и «как правильно». Базовые понятия о реляционных СУБД и языке запросов см. в 07.01 Базы данных и SQL на уровне аналитика.
1. Неправильный порядок ключевых слов
Самая частая ошибка — нарушение порядка следования основных конструкций запроса. В SQL предложения должны идти строго в определённой последовательности: SELECT → FROM → WHERE → ORDER BY.
Ошибочный вариант, где WHERE оказался перед FROM:
select * where range > '5000'
from aircrafts_data
order by rangeПравильный вариант — сначала источник данных, затем условие фильтрации:
SELECT *
FROM aircrafts_data
WHERE range > '5000'
ORDER BY range;Для сортировки по убыванию используется DESC после ORDER BY (по умолчанию действует возрастающий порядок ASC):
SELECT *
FROM aircrafts_data
WHERE range > 5000
ORDER BY range DESC;2. Ошибки при работе с JSONB
При извлечении данных из полей типа JSONB важно учитывать структуру объекта. В примере ниже сразу несколько проблем: неверный порядок WHERE и FROM, а также некорректное условие фильтрации по JSONB-полю.
SELECT aircraft_code, model->>'en' AS aircraft_name
FROM aircrafts_data
WHERE model->>'manufacturer' = 'Boeing'
ORDER BY aircraft_code;Ключевые моменты:
FROMдолжен идти передWHERE;- для извлечения значения из JSONB используется оператор
->>, и условие фильтрации тоже должно обращаться к нужному ключу внутри объекта; - предполагается, что поле
modelсодержит ключmanufacturer.
3. Типы данных и форматы даты/времени
Отдельная категория ошибок связана с несоответствием типов данных и форматов. Если столбец имеет тип DATE или DATETIME, применение оператора LIKE со строковым шаблоном неоптимально — надёжнее использовать диапазоны дат или функции извлечения даты.
Некорректный формат timestamp
Типичная ошибка PostgreSQL — лишние символы в строке даты. Формат '2017-08-01 00:00:00:00' (лишний ноль в конце) приводит к ошибке:
ERROR: invalid input syntax for type timestamp with time zone:
"2017-08-01 00:00:00:00"Ожидаемый формат для timestamp with time zone — 'YYYY-MM-DD HH:MI:SS'. Исправленный запрос:
SELECT *
FROM flights
WHERE departure_airport = 'DME'
AND actual_departure > '2017-08-01 00:00:00'
ORDER BY actual_departure DESC;Фильтрация по конкретному дню
Чтобы выбрать записи за один конкретный день, надёжнее использовать диапазон от начала дня до начала следующего дня, а не сравнение с одной меткой времени. Такой подход корректно захватывает все значения внутри суток:
SELECT *
FROM flights
WHERE departure_airport = 'DME'
AND actual_departure >= '2017-08-01 00:00:00'
AND actual_departure < '2017-08-02 00:00:00'
ORDER BY actual_departure ASC;4. Соответствие запроса заданию
Помимо синтаксической корректности важно проверять, что логика запроса отвечает поставленной задаче. Например, для задания «получить список рейсов, фактически вылетевших из аэропорта Домодедово (DME) 1 августа 2017 г., отсортированных по фактическому времени вылета» запрос выше удовлетворяет всем критериям:
- фильтрация по аэропорту вылета (
departure_airport = 'DME'); - ограничение по дате через диапазон
>= '2017-08-01'и< '2017-08-02'; - сортировка по
actual_departure.
5. Логика условий в WHERE: запятые, алиасы и приоритет операторов
Ещё один класс ошибок связан с построением составных условий фильтрации. Рассмотрим запрос, в котором требовалось найти живых игроков с крупным долгом, являющихся либо пожилыми, либо имеющими пагубную привычку без близких родственников:
SELECT * FROM player
Where p.age > 65, p.status = alive, debt > 400000000 OR vice = Gambling AND has_close_family = 0;Здесь сразу несколько проблем:
- Запятые в условии
WHERE— для объединения условий нужны логические операторыANDилиOR, а не запятые. - Неопределённый алиас
p— алиас используется вp.age, но не объявлен в секцииFROM. Его нужно указать после имени таблицы. - Отсутствие кавычек у строковых значений —
aliveиGamblingдолжны быть заключены в одинарные кавычки. - Приоритет логических операторов — без скобок
ANDиORмогут интерпретироваться не так, как задумано. Приоритет следует задавать явно. - Формат числового значения — значение долга должно соответствовать типу данных столбца
debt.
Исправленный вариант:
SELECT *
FROM player p
WHERE p.status = 'alive'
AND p.debt > 400000000
AND (
p.age > 65
OR (p.vice = 'Gambling' AND p.has_close_family = 0)
);Здесь алиас p определён сразу после имени таблицы, строковые значения взяты в кавычки, запятые заменены логическими операторами, а скобки группируют условия так, чтобы OR применялся только к нужной части выражения.
6. Ошибки при изменении структуры таблиц (ALTER TABLE)
Отдельная категория проблем связана с командой ALTER TABLE, которая изменяет структуру существующей таблицы. Типичная ошибка — при добавлении колонки не указывается её тип данных:
Can't create or update target table:
ALTER TABLE portfolio.yearly_buy ADD "3ffa6dde-e43c-4078-b48c-816455d77369"Возможные причины:
- Ошибка синтаксиса — в команде
ALTER TABLE ... ADDнеобходимо указать имя колонки и её тип данных. В примере указано только значение, похожее на UUID, без типа. - Некорректное имя колонки — использование UUID в качестве имени технически возможно, но крайне не рекомендуется: это усложняет дальнейшую работу с таблицей.
- Недостаточно прав — возможно, у пользователя нет прав на изменение структуры таблицы или схемы.
Корректный синтаксис:
ALTER TABLE portfolio.yearly_buy ADD transaction_id VARCHAR(36);7. Ошибки соединения с СУБД
Помимо синтаксических ошибок в самих запросах, встречаются проблемы на уровне соединения с СУБД. Пример сообщения при подключении к ClickHouse:
ClickHouse exception, code: 210, host: mesprtf-chp1p, port: 9999;
Connect to mesprtf-chp1p:9999 [mesprtf-chp1p/10.15.99.153] failed: Connection refusedТакое сообщение означает, что клиент не может установить соединение с сервером. Это уже не ошибка запроса, а проблема инфраструктуры: недоступный хост, неверный порт, остановленный сервис или блокировка на сетевом уровне. При диагностике стоит сначала проверить доступность сервера и корректность параметров подключения, а не переписывать сам запрос.
8. Итоговая памятка
| Категория ошибки | Что проверить |
|---|---|
| Порядок ключевых слов | SELECT → FROM → WHERE → ORDER BY |
| JSONB | Оператор ->>, обращение к нужному ключу, порядок секций |
| Даты и время | Формат 'YYYY-MM-DD HH:MI:SS', диапазон вместо одной метки |
| Составные условия | AND/OR вместо запятых, кавычки, скобки, алиасы |
ALTER TABLE | Имя колонки и её тип данных, права на изменение |
| Соединение с СУБД | Доступность хоста, порт, состояние сервиса |
Общий принцип: большинство «загадочных» ошибок SQL — это либо нарушение синтаксиса, либо несоответствие типов, либо неявный приоритет операторов. Прежде чем менять логику запроса, стоит внимательно перечитать его структуру и сверить её с требованиями задания.