SQLite на практике
2.38K subscribers
19 photos
84 links
Все о работе с данными в sqlite // antonz.ru
Download Telegram
Сводный запрос по нескольким базам

Если вы настраивали кросс-запросы по нескольким базам в PostgreSQL или Oracle, то знаете, какая эта боль. А в SQLite вот так:

attach database 'moscow.db' as moscow;
attach database 'samara.db' as samara;

select * from moscow.employees
union all
select * from samara.employees;


Удобно, чтобы не переливать данные в одну базу, если они уже лежат в разных.
👍2
SQLite для аналитики

Итак, спустя три месяца курс полностью закончен 🎉

В итоге получилось семь модулей:

1. Основы SQLite.
2. Очистка данных.
3. Связи в данных.
4. Данные → знания.
5. JSON.
6. Большие наборы.
7. Оконные функции.

Самое главное — курс учит получать из данных ответы на вопросы. В этом вся суть прикладного анализа данных.

47 уроков и 130 практических заданий, сертификат для выпускников.

Огромное спасибо бета-тестерам и всем участникам за критику и комментарии! Ваша обратная связь бесценна 🙏

https://antonz.ru/sqlite-course/
👍2
Оконные функции: ранжирование

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

https://antonz.ru/window-ranking/
👍1
Недостающие функции SQLite

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

Поскольку я люблю все упорядочивать, то решил собрать разбросанный по интернету код в единый набор библиотек, с разделением по предметной области и автоматической сборкой для всех ОС.

В программировании на C я не силен, так что дело продвигается не очень быстро. Но кое-что уже удалось сделать:

— математические функции (sqrt, pow, log)
— мат. статистика (median, percentile, stddev)
— строковые функции (reverse, split_part)
— регулярные выражения (like, substr, replace)
— поддержка юникода
— работа с csv как с таблицей

https://github.com/nalgeon/sqlean
👍3
Оконные функции: смещение

Продолжаем разбираться с «окошками». В этой части посмотрим, как сравнивать соседние строки и границы диапазона.

Это одна из неочевидных тем, так что пришлось изготовить особенно много картинок и гифок.

https://antonz.ru/window-offset/
👍1
Помните, я восторгался количеством новых функций в SQLite 3.35? За все надо платить: разработчики выпустили уже пятый патч-релиз (впервые в истории SQLite — раньше было не больше четырех).

Не знаю, какой урок можно из этого извлечь. Разве что «не пихайте много новых фич в один релиз». Хотя звучит довольно очевидно, мы никогда не устаем наступать на эти грабли ツ
👍1
Оконные функции: агрегация

Продолжаем разбираться с «окошками». В этой части посмотрим, как считать суммарные и средние показатели.

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

https://antonz.ru/window-aggregate/
👍3
Добавить или обновить записи одним запросом

Участник курса спрашивает:

Есть таблица, хочу ежедневно загружать в неё обновления из csv. Если по id запись уникальная — добавлять, а если запись существует — обновлять поля, которые отличаются, кроме id. Это можно как-то из коробки?

Да! Такой подход (добавить или обновить по необходимости) в мире SQL называется «upsert». В SQLite он реализуется через инструкцию on conflict.

Допустим, мы хотим добавить/обновить записи в таблице stats. Тогда запрос будет примерно такой:

insert into stats(id, last_updated, usage)
select ... from ...
on conflict(id) do update
set
last_updated = excluded.last_updated,
usage = usage + excluded.usage;


excluded — это та запись, которую мы пытаемся вставить (и она вызвала конфликт по id).

Что особенно приятно, такой же синтаксис сработает и в PostgreSQL (SQLite позаимствовал фичу у него).

P.S. Присоединяйтесь к чату «SQL на практике»! https://t.me/sqliter_chat
👍1
Оконные функции: скользящие агрегаты

Заканчиваем разбираться с оконными функциями. В этой части посмотрим, как считать показатели в динамике — скользящее среднее и сумму нарастающим итогом.

Это последняя статья серии! Гарантирую, что более понятного введения в «окошки» не найдете во всем интернете 💪

https://antonz.ru/window-rolling/
👍2
Курс по оконным функциям

Закончил курс по «окошкам»! 15 уроков, 39 задачек, бессчётное количество картинок и гифок.

Подходит для всех, кто знает обычные селекты и работает с MySQL, PostgreSQL или SQLite.

Стоит 500₽, для выпускников «SQLite для аналитики» — скидка 50%.

https://stepik.org/z/95367
👍1
🤔 Задачка о группах

Подписчик прислал интересную задачку, которая время от времени встречается в реальной жизни. В общем виде звучит так: найти похожие объекты и объединить их в группы.

Рассмотрим на конкретном примере. Есть таблица с атрибутами пользователей:

user_id, attr
1, alpha
1, beta
2, beta
2, gamma
3, delta
3, epsilon
4, delta
4, zeta
5, zeta
5, alpha
6, iota
7, iota
7, kappa
8, kappa
8, lambda


Хотим объединить пользователей в группы. При этом действуют правила:

— Если пользователи A и B обладают общим свойством → они входят в одну группу.
— Если A и B обладают общим свойством P1, B и C обладают общим свойством P2 → A, B, C входят в одну группу.
— Идентификатором группы считается минимальный идентификатор из входящих в нее пользователей.

Для каждой группы хотим еще определить список атрибутов ее пользователей.

В итоге должно получиться две группы:

group_id, user_id, attrs
1, 1, "alpha,beta,gamma,delta,epsilon,zeta"
1, 2, "alpha,beta,gamma,delta,epsilon,zeta"
1, 3, "alpha,beta,gamma,delta,epsilon,zeta"
1, 4, "alpha,beta,gamma,delta,epsilon,zeta"
1, 5, "alpha,beta,gamma,delta,epsilon,zeta"
6, 6, "iota,kappa,lambda"
6, 7, "iota,kappa,lambda"
6, 8, "iota,kappa,lambda”


За сколько запросов возьметесь решить задачу? Каждый CTE или подзапрос считается за отдельный запрос. Использовать процедурные расширения SQL вроде pl/sql и pl/pgSQL — нельзя.

Опрос следует.
За сколько запросов можно решить задачу?
Anonymous Poll
12%
За 1
12%
За 2–3
4%
За 4–6
3%
За 7–10
3%
Никак не решить
66%
Я хлебушек
Первому, кто решит задачу за минимальное количество запросов и сможет объяснить решение — любой мой курс в подарок ツ Пишите → @nalgeon
🤔 Задачка о группах — решение

Увидев задачку о группах, коллега написал мне:

> Человек, порочащий олимпиадное программирование, просит решить задачку ЗА ОДИН запрос. Зачем?

Справедливо. Действительно, главное в решении — не формальное количество запросов, а время на понимание. Поэтому давайте решим без олимпиадного ажиотажа, спокойно и по шагам:

https://antonz.ru/sql-groups/
🔥1
🌤️ SQLite-песочница в браузере

Чего мне всегда не хватало, так это аналога JSFiddle / CodePen для SQL. Онлайн-песочницы, в которой можно быстро проверить запрос и поделиться с другими.

Да, есть SQL Fiddle и DB Fiddle, но оба весьма неудобные, на мой взгляд.

Вот чего хотелось:

— Возможность загрузить готовую базу, а не писать SQL для создания таблиц.
— Подключать как локальные базы, так и удаленные (по url).
— Сохранять базу и запросы в облаке.
— Бесплатно и без регистрации.
— Свежайшая версия SQLite.
— Минимализм.

В общем, сделал сам:
sqlime.org
🔥2
Написал на хабр, как устроена sqlite-песочница в браузере. Если вы немного знакомы с js, может быть интересно → https://habr.com/ru/post/580240/
Табличные выражения 👍

Прием №1, чтобы писать хорошие читаемые SQL-запросы — это табличные выражения (CTE). Люди их боятся, а зря.

Любой подзапрос:

select a, b, c
from (X)
where e = f


Механически превращается в CTE:

with cte_name as (X)
select a, b, c
from cte_name
where e = f


Вот и вся наука, не надо читать увесистую книгу по SQL или проходить курсы.

Существует миф, что «CTE медленные», но на современных СУБД это не так. Да и вообще — как с любым утверждением о медленности чего-либо, всегда можно сравнить два варианта (подзапрос и CTE), если сомневаешься.

Кроме обычных CTE бывают еще рекурсивные — вот это реально злые ребята. А обычные прекрасны, используйте их.
👍4
Мат. статистика в SQLite

Из коробки SQLite поддерживает только min(), max() и avg(). Но с помощью расширения stats легко посчитать медиану, моду, процентили и стандартное отклонение:

select
median(num_pages),
mode(num_pages),
percentile_90(num_pages),
percentile_95(num_pages),
percentile_99(num_pages),
stddev(num_pages)
from books;
🔥1
Найти максимально похожую строку

Подписчик задал интересный вопрос:

Есть строка в переменной str1.
Есть sqlite3 и 600,000 строк внутри.
Как найти макимально приближенно похожую строку в базе? Точного сходства с str1 в базе нет!


Посмотрим на упрощенном примере. Допустим, у нас есть таблица employees, а в ней столбец name:

sqlite> select name from employees;
Дарья
Борис
Елена
Ксения
Леонид
Марина
Иван
Вероника
Григорий
Анна


Хотим найти сотрудника, чье имя больше всего похоже на Вера. Как это сделать?

Если бы в SQLite была функция, которая считает похожесть между двумя строками, все было бы просто:

select
name,
similarity(name, 'Вера') as sim
from employees
order by sim desc
limit 1


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

import sqlite3
from difflib import SequenceMatcher

def similarity(a, b):
ratio = SequenceMatcher(None, a.lower(), b.lower()).ratio()
return round(ratio, 2)

db = sqlite3.connect("employees.db")
db.create_function("similarity", 2, similarity)


Теперь можно выполнить наш запрос:

cursor = db.execute(query)
result = cursor.fetchall()
print(result)


Он вернет самое похожее имя:

[('Вероника', 0.67)]


Ровно то, что мы хотели. Для 600К строк, правда, отработает не слишком быстро.
😱1
Вижу подзапрос → меняю на CTE

Многие студенты (да и не только студенты) обожают многоуровневые SQL-запросы. Пожалуйста, пожалуйста, пожалуйста, не пишите их. Используйте табличные выражения: https://antonz.ru/cte/
👍4
Возможно, странный вопрос, но все равно задам. Вы понимаете, как работают индексы в базе данных?
Final Results
5%
Знаю все нюансы
53%
Понимаю в общих чертах
29%
Знаю только, что индекс ускоряет запросы
13%
Вообще без понятия
😱1