Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Technical Portfolio
GitHub & GitVerse Pages

Интенсив по SQL от Simulative

SQL Lab in JupyterLab

Data & BI Analyst

Для подключения к базе данных PostgreSQL необходимо в окружение установить соответствующий драйвер psycopg2:

# (base) Anaconda Prompt

conda install -n ds-book --override-channels -c conda-forge -c defaults psycopg2
Pandas ver. 3.0.5: порог усечения строк уменьшен до 10
SQLAlchemy ver. 2.0.52: подключение создано
JupySQL ver. 0.11.1: подключен через SQLAlchemy Engine

Интро

Ссылка на Бесплатный интенсив Основы SQL

Вводная инфа

Статьи [1] от Евгения Буторина

Полезности из чата

  • SQL Fiddle - онлайн-редактор (компилятор) SQL-запросов для разных СУБД (MySQL, PostgreSQL, SQLLite ... )


3. Базовый синтаксис

В этом уроке вы сделаете первые уверенные шаги в SQL. Мы разберём, как извлекать данные из таблиц, выбирать конкретные столбцы или все сразу. А чтобы данные были не только полезными, но и удобными для восприятия - научимся сортировать результаты.

Вы изучите:

  • Команду SELECT и выбор нужных колонок

  • Использование псевдонимов (AS)

  • Сортировку результатов с помощью ORDER BY, ASC, DESC

SELECT

Loading...
Loading...

AS

Loading...
Loading...

ORDER BY

ASC

Loading...
Loading...

DESC

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Практика #1

Loading...
Loading...

Куратор

Curse of knowledge (проклятие знания):
Это когда опытный специалист настолько привык к вещам, которые делает каждый день годами, что для него это становится воздухом. Ему кажется: Ну это же очевидно! – и он просто забывает, как на это смотрит человек, делающий первые шаги.


4. Горизонтальная фильтрация

В этом уроке мы научимся вырезать из таблицы только нужные нам строки по определенным условиям, ведь без фильтрации не обходится ни один реальный SQL-запрос.

Вы изучите:

  • Условия сравнения: =, !=, <, >, BETWEEN

  • Логические операторы: AND, OR, NOT

  • Работа с NULL: IS NULL, IS NOT NULL

  • Фильтрацию по строкам, числам и датам

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

AND

Loading...
Loading...

IS NOT NULL

Loading...
Loading...

OR

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

IS NULL

Loading...
Loading...
Loading...
Loading...
RuntimeError: (psycopg2.errors.UndefinedColumn) column "new_col" does not exist
LINE 5: WHERE new_col = 2;
              ^

[SQL: SELECT
	is_active,
	is_active + 1 AS new_col
FROM users
WHERE new_col = 2;]
(Background on this error at: https://sqlalche.me/e/20/f405)
Loading...
Loading...

Практика #2

Loading...
Loading...

Loading...
Loading...
Loading...
Loading...


5. Скалярные функции (текстовые)

В этом уроке мы научимся работать со строками: изменять регистр, обрезать лишнее, извлекать подстроки, склеивать значения и искать/заменять фрагменты. Эти функции пригодятся вам каждый раз, когда нужно почистить или привести к нужному виду текстовые данные.

Вы изучите:

  • Изменение регистра: LOWER, UPPER, INITCAP

  • Работа с длиной и пробелами: LENGTH

  • Извлечение подстрок: LEFT, RIGHT

  • Поиск позиции фрагмента: POSITION

  • Фильтрация по шаблону: LIKE, ILIKE

LOWER( )

Loading...
Loading...
Loading...
Loading...

UPPER( )

Loading...
Loading...

INITCAP( )

Loading...
Loading...
Loading...
Loading...

LIKE( )

Loading...
Loading...

iLIKE( )

Loading...
Loading...

LENGTH( )

Loading...
Loading...
Loading...
Loading...

POSITION( )

Loading...
Loading...

LEFT( )

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Практика #3

Loading...
Loading...

Loading...
Loading...

Loading...
Loading...

Решение 1 (в лоб)

%%sql
SELECT * 
FROM transaction
WHERE LOWER(description) LIKE '% жку %'
   OR LOWER(description) LIKE 'жку %'
   OR LOWER(description) LIKE '% жку'
   OR LOWER(description) = 'жку'
   OR LOWER(description) LIKE '% жкх %'
   OR LOWER(description) LIKE 'жкх %'
   OR LOWER(description) LIKE '% жкх'
   OR LOWER(description) = 'жкх';

Решение 2 (регулярные выражения)

Как эту проблему решают регулярные выражения RegEx:
Регулярные выражения – это специальный язык описания текстовых шаблонов. В PostgreSQL для этого есть оператор ~* (поиск по регулярному выражению без учета регистра). Идеальный и пуленепробиваемый запрос выглядел бы так:

SELECT * FROM transaction
WHERE description ~* '\b(жку|жкх)\b';

Почему это магия:

  • \b – это специальный символ регулярных выражений, который означает граница слова (word boundary).

  • Границей слова движок RegEx считает всё что угодно, кроме букв: пробел, точку, запятую, скобку, начало строки или конец строки.

  • Этот запрос мгновенно найдет “ЖКУ,”, “(ЖКУ)”, “ЖКУ.”, “оплата ЖКУ” и при этом железобетонно проигнорирует “платежку”, потому что между буквой е и ж в слове платежку нет границы слова!

Поэтому регулярные выражения оптимальны: они пишутся в одну строчку и учитывают абсолютно все знаки препинания в мире за один раз.

  • Круглые скобки () создают группу условий. Они ограничивают зону действия вертикальной черты (как скобки в математике).

  • Символ | разделяет варианты внутри этой группы. Конструкция (жку|жкх) говорит движку регулярных выражений: Найди мне либо точную последовательность букв “жку”, ЛИБО последовательность “жкх”. Если бы символа | не существовало, пришлось бы писать два отдельных регулярных выражения и связывать их через привычный SQL-оператор OR:

WHERE description ~* '\bжку\b'
   OR description ~* '\bжкх\b'

Решение 3 (элегантное):

SELECT *
FROM transaction
WHERE INITCAP(description) LIKE '%Жку%'
OR INITCAP(description) LIKE '%Жкх%';
Loading...
Loading...

6. Полезные операторы

В этом уроке продолжаем делать SQL-запросы сложнее. Вы узнаете, как подставить значение по умолчанию, избежать деления на ноль, или применить условную логику прямо в запросе. Эти конструкции особенно полезны, когда работаете с реальными, неидеальными данными.

Вы изучите:

  • Подстановку значений по умолчанию: COALESCE, NULLIF

  • Склеивание строк: CONCAT, ||

  • Ветвление логики через CASE WHEN

  • Работа с NULL и комбинирование выражений

Loading...
Loading...

CONCAT( )

-- Объединяет переменное количество аргументов в одну строку
-- Null значения игнорируются.

CONCAT(expression [, ...])
-- expression - любое выражение для объединения.

Функция concat() и оператор конкатенации || объединяет любое число строк в одну. Но есть различия (см. комментарий в запросе).

Задача: Чтобы обратиться к юзеру, обратимся по имени и фамилии. Если данных нет, будем писать Дорогой клиент.

Loading...
Loading...

CONCAT_WS( )

Когда разделитель один и тот же, удобнее CONCAT_WS (With Separator):
первый аргумент – разделитель, дальше – склеиваемые части.

Loading...
Loading...

COALESCE( )

Загружаем какое-то количество аргументов и COALESCE смотрит значение столбца в каждой строчке на значение аргумента NULL или не NULL.

-- Возвращает первое не-null значение из списка
-- vali - Значения для проверки
COALESCE(val1, val2, ..., valn)

Если val1 не NULL - выводим, если val1 NULL - идем дальше, проверяем val2.
COALESCE выводит первое значение, которое не NULL.

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Используем строку CONCAT(first_name, ' ', last_name) чтобы реализовать конструкцию таким образом: если у нас получилась пустая строка, преобразуем ее в NULL, а потом этот NULL обработает COALESCE и выведет ‘Дорогой клиент’.

Используем вместо CONCAT -> CONCAT_WS, т.к. если у нас много аргументов (много строк нужно объединить), то удобнее написать разделитель только один раз.

NULLIF( )

NULLIF(value_1, value_2)

Сравнивает результат работы первого аргумента и второго аргумента.
Если они совпадают – выводит NULL. Если не совпадают – выводит первый аргумент.

Loading...
Loading...
Loading...
Loading...

Научились превращать пустую строку в NULL, а значит теперь можем пойти обратно в наш запрос и добавить в COALESCE строку NULLIF

Loading...
Loading...

CASE( )

Loading...
Loading...

Как только выполняется одно из условий, оператор останавливается.

Внутри можно наслаивать как угодно, например

WHEN score < 100 AND is_active = 1 THEN 'low'

Применим CASE() к нашей задаче

Loading...

Получили, что если имя NULL, то и фамилия NULL -- т.е. не требуется использовать оба параметра. Возмьмем только имя.

Loading...
Loading...

Практика #4

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

7. Скалярные функции (дата и время)

Работа с датами - одна из самых частых задач в SQL. В этом уроке вы научитесь извлекать нужные части даты, округлять и форматировать её, вычислять разницу между датами и даже прибавлять интервалы.

Вы изучите:

  • Извлечение и округление дат: EXTRACT, DATE_TRUNC, TO_CHAR

  • Арифметика с датами: +, -, INTERVAL

  • Текущая дата и время: NOW()

  • Создание даты вручную: MAKE_DATE

Функции форматирования данных

Loading...
Loading...

Возникают разные задачи:

  • Хотим посмотреть регистрации пользователей помесячно, т.е. нам нужно оставить только год и месяц, отрезать время и дату.

  • Или хотим посмотреть регистрацию пользователей с разбивкой по дням недели.

  • Или посмотреть сколько дней прошло с момента регистрации до совершения первой активности пользователем, т.е. соединяем две таблички регистрация, активность и вычитаем одно из другого, т.е. вычитание дат.

  • Хотим посмотреть сколько времени прошло до покупки.

  • Хотим посмотреть сколько времени прошло между текущим моментом и регистрацией.

  • Хотим посмотреть сколько действий совершил пользователь в течение 3-7-30 дней после регистрации и все это в одном запросе.

Для того, чтобы их решать нужно знать всего лишь парочку функций и просто в нужный момент их применять.

Loading...
Loading...

Первое что нужно научиться делать - это вытаскивать какие-то конкретные части даты или времени. Чаще всего пригождается вытащить год, месяц, день - когда мы просто хотим обрезать время.

TO_CHAR( )

Переводит дату/время или число в строку по нужному формату.

-- PostgreSQL

TO_CHAR(timestamp, format)
--
SELECT TO_CHAR(NOW(), 'YYYY-MM-DD')

timestamp - Значение для преобразования
format - Строка формата

Loading...
Loading...

Не самый эффективный способ работы с датавременем, потому что преобразование типа из одного в другой сжирает какое-то количество ресурсов, особенно если мы фильтрацию по этому какую-то делаем. Но способ настолько простой, что позволяет делать такие конструкции:

Loading...
Loading...

Если у нас огромное количество данных или другие ограничения из-за которых идет борьба за ресурсы и нам нужно ускорять выполнение нашего кода, то приводить датавремя в строку и сравнивать со строкой может быть не самым оптимальным решением.

Но честно скажу, за все время работы прям с реальным ограничением такой конструкции столкнулся 1 раз за 10 лет. Поэтому рекомендую такую конструкцию, т.к. она реально удобна.

Альтернативный вариант:

DATE_TRUNC( )

Обрезает дату/время до указанной точности.

-- PostgreSQL

DATE_TRUNC(field, source)
--
SELECT DATE_TRUNC('month', TIMESTAMP '2023-02-15')

field - определяет до какой точности обрезать входное значение (year, month, day и т.д.)
source - значение даты/времени, выражение типа timestamp, timestamp with time zone или interval. (Значения типов date и time автоматически приводятся к типам timestamp и interval, соответственно.)

Коды форматирования даты/времени

Loading...
Loading...

Для вычитания дат мы можем собрать дату:

MAKE_DATE( )

Создает дату из года, месяца и дня.

MAKE_DATE(year, month, day)
--
SELECT MAKE_DATE(2025, 6, 5)
Loading...
Loading...
Loading...
Loading...

NOW( )

Возвращает текущую дату и время с временной зоной.

NOW()
Loading...
Loading...

Если нас не интересует сколько прошло часов, минут. Если нас интересует сколько прошло, например, дней:

EXTRACT( )

Извлекает подполя из значения даты/времени

EXTRACT(field FROM source)
--
SELECT EXTRACT(
		YEAR
		FROM TIMESTAMP '2023-01-01'
	)

field - Поле для извлечения (year, month, day и т.д.) из значения источника
FROM source - Значение даты/времени; источником должно быть заданное выражением значение типа timestamp, date, time или interval

ВОЗВРАЩАЕТ ЧИСЛО!

  • EXTRACT(year FROM ...) вернёт просто 2021 (число, а не строку).

  • EXTRACT(month FROM ...) вернёт номер месяца: 1, 2 ... 12.

  • EXTRACT(day FROM ...) вернёт день месяца: 1, 15, 31 и т.д.

Поэтому с ней работают обычные математические сравнения с числами: = 2021, > 2020 и т.д.

Loading...
Loading...

Узнать сколько прошло всего часов:

Loading...
Loading...

INTERVAL( )

Loading...
Loading...

Пример конструкции: отфильтровать всех пользователей которые купили подписку в течение 1 суток после регистрации:

WHERE purchase_date BETWEEN date_joined 
                        AND date_joined + INTERVAL '24 hours'

Практка #5

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

DATE

Типизированный литерал стандарта ANSI SQL (Date Literal):

DATE 'YYYY-MM-DD'

-- date + integer → date
-- date + interval → timestamp

Функция извлечения части даты из даты/времени:

DATE(datetime)
--
SELECT DATE('2022-12-05 10:37:22')
Loading...
Loading...

ВАРИАНТЫ: Практика 5. Задача 5

WHERE EXTRACT(year FROM date_joined) = 2021

-- возвращает число 2021, сравниваем с числом 2021
WHERE DATE_TRUNC('year', date_joined) = TIMESTAMP '2021-01-01'

-- явное лучше неявного
                               -- или = '2021-01-01'
                               -- или = DATE '2021-01-01'
                               -- или = MAKE_DATE(2021, 1, 1)
WHERE date_joined >= DATE '2021-01-01' 
  AND date_joined <  DATE '2022-01-01'

/* явное указание типа DATE – признак хорошего тона, хотя
   PostgreSQL легко догадается сам, т.к. слева `timestamp` */
WHERE date_joined BETWEEN '2021-01-01 00:00:00'
                      AND '2021-12-31 23:59:59.999999'

/* чтобы не ловить микросекунды и не писать кучу девяток,
   разработчики баз данных почти никогда не используют 
   `BETWEEN` для дат со временем */

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

8. Дополнительные приемы

Этот короткий, но полезный урок посвящён типичной ошибке - целочисленному делению. Вы поймёте, как она влияет на результаты и как её избежать. Это не только спасёт ваши запросы от неверных результатов, но и прокачает внимание к деталям.

Допустим мы хотим разделить score / 10.

Loading...
Loading...
Loading...
Loading...

Cast оператор ::

Loading...
Loading...

CAST ( )


Loading...
Loading...

Но самый понятный, универсальный и читаемый – это вариант с ROUND:

ROUND(CAST(score AS numeric) / 10, 2)

ROUND( )

Loading...
Loading...

DISTINCT

Loading...
Loading...

9. Соединение таблиц - JOIN

В этом уроке вы научитесь одному из ключевых навыков в SQL - объединению данные из нескольких таблиц. Вы разберётесь в различных типах соединений, научитесь задавать условия и учитывать такие нюансы, как пропущенные строки или дубликаты.

Вы изучите:

  • Виды соединений: INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN

  • Условия соединения ON с несколькими полями

  • Обработка пропусков и дубликатов

Таблица к уроку

Loading...
Loading...

INNER JOIN (JOIN) - берем все строки из первой таблицы, все строки из второй. Оставляем только те строки, по которым нашли соответствие.

LEFT JOIN - из 1-й (левой) таблицы выводим все строки вне зависимости встречаются они в правой таблице или нет. Если встречаются, выводим все значения которые нашли в правой таблице, если не встречаются выводим NULL

FULL JOIN - комбинация левого и правого соединения.

INNER JOIN

Loading...
Loading...
Loading...
Loading...

RIGHT JOIN

Loading...
Loading...
Loading...
Loading...

LEFT JOIN

Loading...
Loading...

Loading...
Loading...
Loading...

Неправильная последовательность JOIN’ов и Неправильный выбор типа соединения приводит к огромному количеству ошибок в сложных запросах.

Loading...
Loading...

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Footnotes
  1. Читай статьи Евгения Буторина – прям реално лучше поймешь лекции и проще будет делать практику.

  2. Google Colab