Язык SQL: SELECT, WHERE и сортировка

Главный навык работы с базами: задавать вопросы данным на языке SQL и получать точные ответы.

SQL (Structured Query Language) — язык запросов к реляционным базам данных; на нём вы описываете, что хотите получить, а СУБД сама решает, как это сделать.

Зачем это нужно

База данных бесполезна, если из неё нельзя достать нужное. SQL — универсальный язык, понятный всем реляционным СУБД (SQLite, PostgreSQL, MySQL). Запрос SELECT — самая частая операция в IT вообще: «покажи всех пользователей старше 18», «найди заказы за вчера», «сколько товаров на складе». Освоив SELECT с условиями и сортировкой, вы научитесь извлекать из данных ответы — а это и есть суть работы с базами. Все примеры запускаются в живой песочнице.

У SQL есть особенность, которая поначалу удивляет тех, кто уже писал на Python: это декларативный язык. В обычной программе вы пошагово описываете, как получить результат — заведи переменную, пройди циклом, сравни, добавь. В SQL вы описываете только что хотите получить — «названия и цены товаров дешевле ста рублей, по возрастанию цены», — а как это найти, решает сама СУБД. Внутри она применяет хитрые алгоритмы и индексы, выбирает оптимальный план выполнения, но всё это скрыто от вас. Такой подход невероятно мощен: один короткий запрос может за доли секунды обработать миллионы строк, и вам не нужно знать, какой именно алгоритм при этом сработал. Привыкнуть к декларативному мышлению — главный концептуальный шаг этого урока: перестаньте думать «как перебрать данные» и начните думать «как описать нужный результат».

Готовим данные

Чтобы запросы было к чему применять, в каждом примере мы сначала создаём и наполняем таблицу, а затем делаем выборку — так блок самодостаточен. Вот наша таблица товаров:

CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,
    category TEXT,
    price INTEGER,
    stock INTEGER
);

INSERT INTO products (name, category, price, stock) VALUES
    ('Тетрадь',   'канцелярия', 40,  120),
    ('Ручка',     'канцелярия', 25,  300),
    ('Рюкзак',    'сумки',      1500, 15),
    ('Пенал',     'канцелярия', 350, 40),
    ('Калькулятор','электроника',900, 8),
    ('Линейка',   'канцелярия', 30,  200);

SELECT name, price FROM products;

Вывод:

name        | price
Тетрадь     | 40
Ручка       | 25
Рюкзак      | 1500
Пенал       | 350
Калькулятор | 900
Линейка     | 30

SELECT: выбираем нужные столбцы

После SELECT перечисляют поля, которые хотят увидеть; FROM указывает таблицу. Звёздочка * означает «все поля». Выбирайте только нужное — это и понятнее, и быстрее. В примере выше мы взяли только название и цену, хотя в таблице есть и другие поля.

WHERE: фильтруем строки по условию

Условие WHERE оставляет только те строки, которые ему удовлетворяют. Это сердце большинства запросов. Поддерживаются сравнения (=, <, >, <=, >=, <>) и логические AND, OR, NOT. Найдём недорогие товары в наличии:

CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT, category TEXT, price INTEGER, stock INTEGER
);
INSERT INTO products (name, category, price, stock) VALUES
    ('Тетрадь','канцелярия',40,120), ('Ручка','канцелярия',25,300),
    ('Рюкзак','сумки',1500,15), ('Пенал','канцелярия',350,40),
    ('Калькулятор','электроника',900,8), ('Линейка','канцелярия',30,200);

SELECT name, price, stock
FROM products
WHERE price < 100 AND stock > 0;

Вывод:

name    | price | stock
Тетрадь | 40    | 120
Ручка   | 25    | 300
Линейка | 30    | 200

ORDER BY: сортируем результат

ORDER BY упорядочивает строки по выбранному полю: ASC — по возрастанию (по умолчанию), DESC — по убыванию. Выведем товары от самого дорогого к дешёвому, а LIMIT покажет только верхушку списка:

CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT, category TEXT, price INTEGER, stock INTEGER
);
INSERT INTO products (name, category, price, stock) VALUES
    ('Тетрадь','канцелярия',40,120), ('Ручка','канцелярия',25,300),
    ('Рюкзак','сумки',1500,15), ('Пенал','канцелярия',350,40),
    ('Калькулятор','электроника',900,8), ('Линейка','канцелярия',30,200);

SELECT name, price
FROM products
ORDER BY price DESC
LIMIT 3;

Вывод:

name        | price
Рюкзак      | 1500
Калькулятор | 900
Пенал       | 350

LIKE и IN: гибкий поиск

LIKE ищет по шаблону: % заменяет любое число символов, _ — один. IN проверяет принадлежность к списку значений. Эти операторы делают условия выразительнее. Найдём товары канцелярии или сумок, и отдельно — те, чьё название содержит «ка»:

CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT, category TEXT, price INTEGER, stock INTEGER
);
INSERT INTO products (name, category, price, stock) VALUES
    ('Тетрадь','канцелярия',40,120), ('Ручка','канцелярия',25,300),
    ('Рюкзак','сумки',1500,15), ('Пенал','канцелярия',350,40),
    ('Калькулятор','электроника',900,8), ('Линейка','канцелярия',30,200);

SELECT name, category
FROM products
WHERE category IN ('канцелярия', 'сумки')
  AND name LIKE '%ка%'
ORDER BY name;

Вывод:

name    | category
Линейка | канцелярия
Ручка   | канцелярия

Вычисляемые столбцы

В SELECT можно не только выбирать поля, но и вычислять новые. Псевдоним AS даёт результату удобное имя. Посчитаем стоимость остатка каждого товара (цена × количество):

CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT, category TEXT, price INTEGER, stock INTEGER
);
INSERT INTO products (name, category, price, stock) VALUES
    ('Тетрадь','канцелярия',40,120), ('Ручка','канцелярия',25,300),
    ('Рюкзак','сумки',1500,15), ('Пенал','канцелярия',350,40),
    ('Калькулятор','электроника',900,8), ('Линейка','канцелярия',30,200);

SELECT name, price * stock AS total_value
FROM products
ORDER BY total_value DESC;

Вывод:

name        | total_value
Рюкзак      | 22500
Пенал       | 14000
Ручка       | 7500
Калькулятор | 7200
Линейка     | 6000
Тетрадь     | 4800

Попробуй сам

Соберите запрос-отчёт: товары канцелярии дороже 30 рублей, отсортированные по цене, с вычисленной ценой со скидкой 10%. Меняйте условия и порядок — песочница покажет результат мгновенно.

CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT, category TEXT, price INTEGER, stock INTEGER
);
INSERT INTO products (name, category, price, stock) VALUES
    ('Тетрадь','канцелярия',40,120), ('Ручка','канцелярия',25,300),
    ('Рюкзак','сумки',1500,15), ('Пенал','канцелярия',350,40),
    ('Калькулятор','электроника',900,8), ('Линейка','канцелярия',30,200);

SELECT name,
       price,
       price * 0.9 AS sale_price
FROM products
WHERE category = 'канцелярия' AND price > 30
ORDER BY price;

Вывод:

name    | price | sale_price
Тетрадь | 40    | 36.0
Пенал   | 350   | 315.0

Частые ошибки

  • Путают = и ==. В SQL сравнение на равенство — это один знак =, а не два.
  • Забывают кавычки у текста. Строковые значения в условиях берут в одинарные кавычки: category = 'сумки'.
  • Пишут ORDER BY перед WHERE. Порядок частей строгий: SELECT … FROM … WHERE … ORDER BY … LIMIT.
  • Ждут от LIKE регистронезависимости везде. Поведение LIKE с регистром зависит от СУБД; для надёжности приводят регистр функциями.

Итоги

  • SELECT поля FROM таблица — базовая выборка; * берёт все поля.
  • WHERE фильтрует строки по условию с операторами сравнения и AND/OR/NOT.
  • ORDER BY поле [DESC] сортирует, LIMIT n ограничивает число строк.
  • LIKE ищет по шаблону (%, _), IN — по списку; AS именует вычисляемые столбцы.
Проверьте себя
1. Какая часть SQL-запроса отвечает за фильтрацию строк по условию?
ASELECT
BFROM
CWHERE
DORDER BY
2. Что выведет ORDER BY price DESC?
Aстроки по возрастанию цены
Bстроки по убыванию цены
Cтолько строку с максимальной ценой
Dстроки в случайном порядке
3. Как в SQL найти все названия, начинающиеся на букву 'Р'?
AWHERE name = 'Р%'
BWHERE name LIKE 'Р%'
CWHERE name IN ('Р')
DWHERE name > 'Р'
Поддержать проект