Кладовочка

О разном, чтобы было под рукой онлайн

SQL шпаргалка для начинающих: базовые запросы, JOIN, GROUP BY, подзапросы

Эта шпаргалка — для тех, кто начинает учить SQL или периодически забывает синтаксис. Здесь только база — JOIN, GROUP BY, подзапросы — то, что используется каждый день. Для продвинутых тем (оконные функции, CTE, сравнение диалектов) — отдельная шпаргалка по продвинутому SQL.

SELECT — получение данных

-- Выбрать всё
SELECT * FROM users;

-- Выбрать конкретные столбцы
SELECT name, email, created_at FROM users;

-- Убрать дубликаты
SELECT DISTINCT city FROM users;

-- Псевдонимы (алиасы)
SELECT name AS full_name, email AS contact FROM users;

-- Вычисляемые поля
SELECT name, salary * 12 AS annual_salary FROM employees;

-- Ограничение числа строк
SELECT * FROM users LIMIT 10;
SELECT * FROM users LIMIT 10 OFFSET 20;  -- строки 21–30
-- В MySQL: LIMIT 20, 10 (смещение первым!)

WHERE — фильтрация

-- Операторы сравнения: =, !=, <>, <, >, <=, >=
SELECT * FROM products WHERE price > 100;

-- AND / OR / NOT
SELECT * FROM users WHERE age >= 18 AND country = 'RU';
SELECT * FROM users WHERE country = 'RU' OR country = 'BY';
SELECT * FROM users WHERE NOT status = 'deleted';

-- BETWEEN — диапазон
SELECT * FROM orders WHERE amount BETWEEN 100 AND 500;

-- IN — список значений
SELECT * FROM users WHERE country IN ('RU', 'BY', 'KZ');

-- LIKE — поиск по шаблону (% — любые символы, _ — один символ)
SELECT * FROM users WHERE name LIKE 'А%';     -- начинается на А
SELECT * FROM users WHERE email LIKE '%@gmail%';  -- содержит gmail
SELECT * FROM users WHERE phone LIKE '+7___';  -- +7 и три цифры после

-- IS NULL / IS NOT NULL
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE phone IS NOT NULL;

ORDER BY — сортировка

-- По одному полю
SELECT * FROM products ORDER BY price;           -- по возрастанию
SELECT * FROM products ORDER BY price DESC;      -- по убыванию

-- По нескольким полям
SELECT * FROM orders ORDER BY customer_id, order_date DESC;

-- С LIMIT — топ-N
SELECT * FROM products ORDER BY sales_count DESC LIMIT 10;

-- Случайный порядок (разный синтаксис!)
-- PostgreSQL: ORDER BY RANDOM()
-- MySQL: ORDER BY RAND()
-- SQLite: ORDER BY RANDOM()
-- Oracle: ORDER BY DBMS_RANDOM.VALUE

Агрегатные функции и GROUP BY

-- Агрегатные функции
SELECT COUNT(*) FROM orders;                     -- количество строк
SELECT COUNT(DISTINCT customer_id) FROM orders;  -- уникальных клиентов
SELECT SUM(amount) FROM orders;                  -- сумма
SELECT AVG(amount) FROM orders;                  -- среднее
SELECT MIN(amount), MAX(amount) FROM orders;     -- минимум, максимум

-- GROUP BY — группировка
SELECT customer_id, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id;

-- Группировка по нескольким полям
SELECT customer_id, status, SUM(amount) AS total
FROM orders
GROUP BY customer_id, status;

-- HAVING — фильтрация после группировки (WHERE — до)
SELECT customer_id, SUM(amount) AS total
FROM orders
GROUP BY customer_id
HAVING SUM(amount) > 1000;

-- Полный порядок запроса:
-- SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT ...

JOIN — соединение таблиц

-- INNER JOIN — только совпадающие строки
SELECT u.name, o.amount, o.order_date
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

-- LEFT JOIN — все строки из левой таблицы
SELECT u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Вернёт ВСЕХ пользователей, даже без заказов (o.amount будет NULL)

-- RIGHT JOIN — все строки из правой
SELECT u.name, o.amount
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
-- Вернёт ВСЕ заказы, даже если пользователь удалён

-- FULL OUTER JOIN — все строки из обеих таблиц
SELECT u.name, o.amount
FROM users u
FULL OUTER JOIN orders o ON u.id = o.user_id;

-- JOIN нескольких таблиц
SELECT u.name, o.id AS order_id, p.name AS product, oi.quantity
FROM users u
JOIN orders o ON u.id = o.user_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id;

-- SELF JOIN — соединение таблицы с собой (иерархия сотрудников)
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;

-- CROSS JOIN — декартово произведение
SELECT * FROM colors CROSS JOIN sizes;

-- JOIN с дополнительными условиями
SELECT u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id AND o.status = 'paid';

Подзапросы

-- В WHERE — скалярный подзапрос
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- В WHERE — с IN (подзапрос возвращает список)
SELECT name
FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 1000);

-- В WHERE — с EXISTS (проверка существования)
SELECT name
FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);

-- В SELECT — скалярный подзапрос
SELECT name,
       salary,
       (SELECT AVG(salary) FROM employees) AS avg_salary,
       salary - (SELECT AVG(salary) FROM employees) AS diff
FROM employees;

-- В FROM — производная таблица
SELECT dept, avg_sal
FROM (
    SELECT department AS dept, AVG(salary) AS avg_sal
    FROM employees
    GROUP BY department
) AS dept_stats
WHERE avg_sal > 100000;

-- Коррелированный подзапрос (ссылается на внешний запрос)
SELECT name, salary
FROM employees e1
WHERE salary > (SELECT AVG(salary) FROM employees e2 WHERE e2.department = e1.department);

UNION — объединение результатов

-- UNION — убирает дубликаты
SELECT name, email FROM customers
UNION
SELECT name, email FROM suppliers;

-- UNION ALL — сохраняет все строки (быстрее)
SELECT name FROM active_users
UNION ALL
SELECT name FROM archived_users;

-- Правила: одинаковое число столбцов, совместимые типы, ORDER BY в конце
SELECT name, 'клиент' AS type FROM customers
UNION
SELECT name, 'поставщик' FROM suppliers
ORDER BY name;

INSERT, UPDATE, DELETE — изменение данных

-- INSERT — вставка строк
INSERT INTO users (name, email, age) VALUES ('Alice', 'alice@ex.com', 30);
INSERT INTO users (name, email, age) VALUES
    ('Bob', 'bob@ex.com', 25),
    ('Carol', 'carol@ex.com', 28);

-- INSERT из SELECT
INSERT INTO premium_users (id, name)
SELECT id, name FROM users WHERE total_orders > 50;

-- UPDATE — обновление
UPDATE users SET status = 'active' WHERE id = 42;
UPDATE users SET salary = salary * 1.1 WHERE department = 'Engineering';

-- DELETE — удаление
DELETE FROM users WHERE status = 'deleted' AND last_login < '2025-01-01';

-- TRUNCATE — очистка всей таблицы (быстрее DELETE без WHERE)
TRUNCATE TABLE temp_logs;

CREATE, ALTER, DROP — DDL

-- Создание таблицы
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE,
    age INTEGER CHECK (age >= 0),
    role VARCHAR(50) DEFAULT 'user',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Внешний ключ
CREATE TABLE orders (
    id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL,
    amount DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Автоинкремент (разный синтаксис!)
-- PostgreSQL: id SERIAL PRIMARY KEY
-- MySQL: id INT AUTO_INCREMENT PRIMARY KEY
-- SQLite: id INTEGER PRIMARY KEY (автоматически!)
-- Oracle: id NUMBER GENERATED AS IDENTITY

-- ALTER TABLE — изменение структуры
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users DROP COLUMN phone;
ALTER TABLE users RENAME COLUMN name TO full_name;
ALTER TABLE users ALTER COLUMN email SET NOT NULL;

-- Индексы
CREATE INDEX idx_users_email ON users(email);
CREATE UNIQUE INDEX idx_users_phone ON users(phone);
DROP INDEX idx_users_email;

-- Удаление таблицы
DROP TABLE IF EXISTS temp_data;

Основные встроенные функции

-- Строковые
SELECT UPPER(name), LOWER(email) FROM users;
SELECT LENGTH(name) FROM users;          -- MySQL: байты! лучше CHAR_LENGTH()
SELECT SUBSTRING(name FROM 1 FOR 3) FROM users;
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;
SELECT TRIM(name) FROM users;            -- убрать пробелы по краям
SELECT REPLACE(description, 'old', 'new') FROM products;

-- Числовые
SELECT ROUND(price, 2), CEIL(price), FLOOR(price) FROM products;
SELECT ABS(balance), POWER(amount, 2), SQRT(value) FROM data;

-- Дата и время (различаются!)
SELECT CURRENT_DATE;                     -- сегодня
SELECT CURRENT_TIMESTAMP;                -- сейчас
SELECT EXTRACT(YEAR FROM created_at) FROM users;
SELECT DATE_PART('month', created_at) FROM users;  -- PostgreSQL
SELECT MONTH(created_at) FROM users;                -- MySQL

-- Преобразование типов
SELECT CAST(amount AS INTEGER) FROM orders;
SELECT amount::INTEGER FROM orders;      -- PostgreSQL
SELECT amount::VARCHAR FROM orders;       -- PostgreSQL

-- COALESCE — первое не-NULL значение
SELECT name, COALESCE(phone, 'не указан') AS phone FROM users;

-- NULLIF — вернуть NULL если значения равны
SELECT NULLIF(dividend, 0) FROM data;    -- избежать деления на 0

-- CASE — условная логика
SELECT name,
       CASE
           WHEN salary < 50000 THEN 'low'
           WHEN salary < 100000 THEN 'medium'
           ELSE 'high'
       END AS salary_level
FROM employees;

Транзакции

-- Явная транзакция
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT;  -- или ROLLBACK при ошибке

-- Точка сохранения
BEGIN;
UPDATE orders SET status = 'shipped' WHERE id = 42;
SAVEPOINT shipped;
UPDATE orders SET status = 'delivered' WHERE id = 42;
-- Можно откатить к точке: ROLLBACK TO shipped;
COMMIT;

Таблица частых ошибок

Ошибка Пример Как исправить
= вместо == WHERE name == 'Alice' WHERE name = 'Alice'
Одинарные кавычки для строк WHERE name = "Alice" WHERE name = 'Alice'
Путаница WHERE и HAVING HAVING amount > 100 (без GROUP BY) WHERE amount > 100
NULL = NULL WHERE phone = NULL WHERE phone IS NULL
Группировка без агрегации SELECT name, COUNT(*) FROM users SELECT name, COUNT(*) FROM users GROUP BY name
LIMIT без ORDER BY SELECT * FROM t LIMIT 10 SELECT * FROM t ORDER BY id LIMIT 10
Таблица в GROUP BY, поле в SELECT — не то же SELECT department, AVG(salary) FROM employees GROUP BY department
Забыт алиас для подзапроса в FROM FROM (SELECT ...) FROM (SELECT ...) AS t

Что дальше

База освоена. Дальше — продвинутые темы:


Связанные статьи: SQL для продвинутых, 50+ инструментов разработчика 2025, Шпаргалка Docker: команды и Dockerfile