В статье рассказывается о том, как грамотно организовать резервное копирование PostgreSQL с помощью стандартных инструментов командной строки.
Автор подробно сравнивает форматы дампов (plain, custom, tar, directory), объясняет, в каких сценариях лучше использовать каждый из них, и показывает замеры по времени, объёму и возможностям восстановления.
tags: #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤2
Please open Telegram to view this post
VIEW IN TELEGRAM
😁24🔥3👍1
Почему в
WHERE нельзя использовать алиасы из SELECT?Ответ:
tags: #собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯10👍9❤5
Делимся книгой для тех, кто хочет разобраться, как устроены современные СУБД на уровне архитектуры, алгоритмов и структур данных.
Подойдет разработчикам и архитекторам, которым важно понимать внутреннюю логику систем, а не просто применять готовые решения по шаблону.
tags: #полезное
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍4❤1
Forwarded from Data Science. SQL hub
Media is too big
VIEW IN TELEGRAM
📜 История SQL — от лабораторной идеи до «языка данных» № 1
Как появился самый известный язык работы с базами, почему он едва не остался «Сиквелом» и какие любопытные факты о нём редко всплывают в учебниках.
1. Всё началось с таблицы на бумаге
- 1970 г. — британский математик Эдгар Ф. Кодд публикует культовую статью *“A Relational Model of Data for Large Shared Data Banks”*.
- В ней впервые прозвучала идея: хранить данные в виде связанных таблиц, а не как запутанные иерархии (IMS) или сетевые графы (Codasyl).
- Коллеги в IBM скептически называли это «бумагой на буквы», но разрешили сделать прототип, чтобы проверить утопию Кодда на практике.
2. SEQUEL — «английский» запрос к таблицам
- 1973–1974 гг. — в лаборатории IBM San José (ныне Almaden) двое молодых исследователей, Дональд Чемберлин и Рэймонд Бойс, берутся за проект System R.
- Чтобы обращаться к реляционным таблицам, они придумывают Structured English QUEry Language — SEQUEL.
- Ключевая фишка — запросы выглядят почти как английские предложения:
- В 1974‑м публикуют первую спецификацию; академики критикуют за «слишком поверхностный английский», но программисты в восторге.
3. Почему SEQUEL стал SQL
- Торговая марка “SEQUEL” уже принадлежала авиастроительной компании *Hawker Siddeley*.
- IBM, опасаясь суда, в 1976 г. официально отказывается от «E» и оставляет SQL (Structured Query Language).
- *Небольшая путаница осталась навсегда: кто‑то произносит «эс‑кью‑эл», кто‑то — «сиквел».*
4. Коммерческий взлёт
- 1978 | Первая демонстрация System R внутри IBM | показала, что SQL работает быстрее ожиданий |
- 1979 | Стартап Relational Software (позже Oracle**) выпускает **Oracle V2 — первый коммерческий SQL‑движок | IBM ещё не успела выйти на рынок
- 1981 | IBM выпускает SQL/DS для мейнфреймов | стандарт де‑факто закрепляется
- 1983 | Дебют DB2 — теперь SQL есть почти в каждом крупном банке
5. Стандартизация и эволюция
- ANSI SQL‑86 → SQL‑92 (появился `JOIN ... ON`) → SQL:1999 (рекурсия, триггеры) → SQL:2003 (XML) → … → SQL:2023 (JSON, property graphs).
- Каждые 3–5 лет комитет добавляет «модные» возможности, но 90 % повседневных запросов всё ещё укладываются в синтаксис 1980‑х.
6. Забавные факты, которые украсят small talk 🍸
1. NULL ≠ 0 и NULL ≠ NULL — «неизвестное значение» нарушает законы логики, за что его зовут *“пятой ногой”* реляционной алгебры.
2. `SELECT *` — наследие печати на станке. Звёздочка означала «все колонки», чтобы не писать их руками в 132‑символьных перфокартах.
3. Команда
4. В Oracle долго не было
5. Первый SQL‑вирус — червь *Slammer* (2003) — парализовал интернет за 10 минут через уязвимость в SQL Server 2000.
6. SQL — декларативный язык, но внутри СУБД каждый
7.Ф. Кодд публикуетпридумали позже, чемлабораторн Сначала удалять целую БД казалось слишком опасным.
7. Почему SQL живёт дольше модных NoSQL‑наследников
- Математическая база. Таблицы + операции Кодда образуют алгебру с предсказуемой оптимизацией.
- Стандарты и переносимость. Код двадцатилетней давности можно запустить в современной Postgres или MariaDB.
- Большая экосистема. От Excel‑плагинов до BigQuery — везде так или иначе поддерживается SQL‑диалект.
- Сопротивляемость моде. Каждый «убийца SQL» (MapReduce, GraphQL, документные БД) в итоге добавляет свой адаптер
Итог: SQL родился как эксперимент IBM, пережил смену названий и юридические баталии, но в итоге стал «лентой Мёбиуса» мира данных: можно зайти с любой стороны — и всё равно окажешься в
https://www.youtube.com/shorts/EuFjzuVHkHE
@sqlhub -подписаться
Как появился самый известный язык работы с базами, почему он едва не остался «Сиквелом» и какие любопытные факты о нём редко всплывают в учебниках.
1. Всё началось с таблицы на бумаге
- 1970 г. — британский математик Эдгар Ф. Кодд публикует культовую статью *“A Relational Model of Data for Large Shared Data Banks”*.
- В ней впервые прозвучала идея: хранить данные в виде связанных таблиц, а не как запутанные иерархии (IMS) или сетевые графы (Codasyl).
- Коллеги в IBM скептически называли это «бумагой на буквы», но разрешили сделать прототип, чтобы проверить утопию Кодда на практике.
2. SEQUEL — «английский» запрос к таблицам
- 1973–1974 гг. — в лаборатории IBM San José (ныне Almaden) двое молодых исследователей, Дональд Чемберлин и Рэймонд Бойс, берутся за проект System R.
- Чтобы обращаться к реляционным таблицам, они придумывают Structured English QUEry Language — SEQUEL.
- Ключевая фишка — запросы выглядят почти как английские предложения:
SELECT name, salary
FROM employees
WHERE dept = 'R&D';
- В 1974‑м публикуют первую спецификацию; академики критикуют за «слишком поверхностный английский», но программисты в восторге.
3. Почему SEQUEL стал SQL
- Торговая марка “SEQUEL” уже принадлежала авиастроительной компании *Hawker Siddeley*.
- IBM, опасаясь суда, в 1976 г. официально отказывается от «E» и оставляет SQL (Structured Query Language).
- *Небольшая путаница осталась навсегда: кто‑то произносит «эс‑кью‑эл», кто‑то — «сиквел».*
4. Коммерческий взлёт
- 1978 | Первая демонстрация System R внутри IBM | показала, что SQL работает быстрее ожиданий |
- 1979 | Стартап Relational Software (позже Oracle**) выпускает **Oracle V2 — первый коммерческий SQL‑движок | IBM ещё не успела выйти на рынок
- 1981 | IBM выпускает SQL/DS для мейнфреймов | стандарт де‑факто закрепляется
- 1983 | Дебют DB2 — теперь SQL есть почти в каждом крупном банке
5. Стандартизация и эволюция
- ANSI SQL‑86 → SQL‑92 (появился `JOIN ... ON`) → SQL:1999 (рекурсия, триггеры) → SQL:2003 (XML) → … → SQL:2023 (JSON, property graphs).
- Каждые 3–5 лет комитет добавляет «модные» возможности, но 90 % повседневных запросов всё ещё укладываются в синтаксис 1980‑х.
6. Забавные факты, которые украсят small talk 🍸
1. NULL ≠ 0 и NULL ≠ NULL — «неизвестное значение» нарушает законы логики, за что его зовут *“пятой ногой”* реляционной алгебры.
2. `SELECT *` — наследие печати на станке. Звёздочка означала «все колонки», чтобы не писать их руками в 132‑символьных перфокартах.
3. Команда
GO в MS SQL Server не принадлежит стандарту SQL — это директива из старого клиента isql. 4. В Oracle долго не было
LIMIT, а в MySQL —QL — от лабора Поэтому админы шутили: «истинный межплатформенный SQL — это `SELECT 1;`». 5. Первый SQL‑вирус — червь *Slammer* (2003) — парализовал интернет за 10 минут через уязвимость в SQL Server 2000.
6. SQL — декларативный язык, но внутри СУБД каждый
SELECT превращается в процедурный план. 7.Ф. Кодд публикуетпридумали позже, чемлабораторн Сначала удалять целую БД казалось слишком опасным.
7. Почему SQL живёт дольше модных NoSQL‑наследников
- Математическая база. Таблицы + операции Кодда образуют алгебру с предсказуемой оптимизацией.
- Стандарты и переносимость. Код двадцатилетней давности можно запустить в современной Postgres или MariaDB.
- Большая экосистема. От Excel‑плагинов до BigQuery — везде так или иначе поддерживается SQL‑диалект.
- Сопротивляемость моде. Каждый «убийца SQL» (MapReduce, GraphQL, документные БД) в итоге добавляет свой адаптер
SELECT ….Итог: SQL родился как эксперимент IBM, пережил смену названий и юридические баталии, но в итоге стал «лентой Мёбиуса» мира данных: можно зайти с любой стороны — и всё равно окажешься в
FROM.https://www.youtube.com/shorts/EuFjzuVHkHE
@sqlhub -подписаться
👍23🔥11❤4🤨4🥰1💊1
Друзья, мы создали канал с книгами по SQL и залили туда наверное самую большую подборку книг по SQL. Около 200 книг. Каждую неделю выходят еще новые книги.
Подпишитесь, там будут книги и марафоны задач по SQL и много редкой литературы. https://t.me/sql_lib
Подпишитесь, там будут книги и марафоны задач по SQL и много редкой литературы. https://t.me/sql_lib
Telegram
Библиотека баз данных
Самая большая библиотека бесплатных книг по SQL
По всем вопросам- @haarrp
@ai_machinelearning_big_data - machine learning
@pythonl - Python
@itchannels_telegram - 🔥 best it channels
@ArtificialIntelligencedl - AI
РКН: № 5037640984
По всем вопросам- @haarrp
@ai_machinelearning_big_data - machine learning
@pythonl - Python
@itchannels_telegram - 🔥 best it channels
@ArtificialIntelligencedl - AI
РКН: № 5037640984
👍7❤2🔥2💊2🤨1
🛢️ SQL-задача с подвохом: NULL ловушка
Условие:
Есть таблица
| id | name | department |
|-----|----------|------------|
| 1 | Alice | Sales |
| 2 | Bob | NULL |
| 3 | Charlie | HR |
| 4 | Diana | NULL |
| 5 | Eve | Sales |
Ты хочешь выбрать всех сотрудников, которые не работают в отделе Sales. Пишешь простой запрос:
❓ Вопрос:
Какие строки вернёт этот запрос? Почему результат может удивить даже опытных специалистов?
---
🔍 Разбор:
На первый взгляд логика понятна: мы хотим исключить сотрудников из отдела
- Bob (NULL)
- Charlie (HR)
- Diana (NULL)
Но вот главный подвох: NULL — это "неизвестное значение", и в SQL любые сравнения с NULL дают
Запрос:
- Charlie (HR): ✅ вернётся, потому что HR <> Sales.
- Bob (NULL): ❌ НЕ вернётся, потому что NULL <> 'Sales' даёт
- Diana (NULL): ❌ по той же причине.
- Alice и Eve: ❌ потому что у них Sales.
---
✅ Фактический результат:
| id | name | department |
|-----|---------|------------|
| 3 | Charlie | HR |
---
💥 Подвох:
Многие думают, что NULL автоматически участвует в сравнении как будто это "значение", но SQL строго следует трёхзначной логике:
- TRUE
- FALSE
- UNKNOWN
В
---
🛠 Как исправить запрос, чтобы включить сотрудников без отдела (NULL):
Теперь вернётся:
| id | name | department |
|-----|---------|------------|
| 2 | Bob | NULL |
| 3 | Charlie | HR |
| 4 | Diana | NULL |
---
✅ Вывод:
• В SQL сравнения с NULL всегда возвращают
• Обычные условия (`<>`,
• Даже простой фильтр может дать неожиданный результат, если в данных есть пропуски.
💡 Бонус-вопрос:
Что будет, если использовать
➡ SQL Community |
Условие:
Есть таблица
employees:| id | name | department |
|-----|----------|------------|
| 1 | Alice | Sales |
| 2 | Bob | NULL |
| 3 | Charlie | HR |
| 4 | Diana | NULL |
| 5 | Eve | Sales |
Ты хочешь выбрать всех сотрудников, которые не работают в отделе Sales. Пишешь простой запрос:
SELECT * FROM employees
WHERE department <> 'Sales';
❓ Вопрос:
Какие строки вернёт этот запрос? Почему результат может удивить даже опытных специалистов?
---
🔍 Разбор:
На первый взгляд логика понятна: мы хотим исключить сотрудников из отдела
Sales. Кажется, что должны вернуться:- Bob (NULL)
- Charlie (HR)
- Diana (NULL)
Но вот главный подвох: NULL — это "неизвестное значение", и в SQL любые сравнения с NULL дают
UNKNOWN.Запрос:
WHERE department <> 'Sales'
- Charlie (HR): ✅ вернётся, потому что HR <> Sales.
- Bob (NULL): ❌ НЕ вернётся, потому что NULL <> 'Sales' даёт
UNKNOWN (не TRUE). - Diana (NULL): ❌ по той же причине.
- Alice и Eve: ❌ потому что у них Sales.
---
✅ Фактический результат:
| id | name | department |
|-----|---------|------------|
| 3 | Charlie | HR |
---
💥 Подвох:
Многие думают, что NULL автоматически участвует в сравнении как будто это "значение", но SQL строго следует трёхзначной логике:
- TRUE
- FALSE
- UNKNOWN
В
WHERE фильтре остаются только строки, где условие = TRUE. Строки с NULL дают UNKNOWN и отбрасываются.---
🛠 Как исправить запрос, чтобы включить сотрудников без отдела (NULL):
SELECT * FROM employees
WHERE department <> 'Sales' OR department IS NULL;
Теперь вернётся:
| id | name | department |
|-----|---------|------------|
| 2 | Bob | NULL |
| 3 | Charlie | HR |
| 4 | Diana | NULL |
---
✅ Вывод:
• В SQL сравнения с NULL всегда возвращают
UNKNOWN. • Обычные условия (`<>`,
=, >, <`) **не учитывают NULL правильно**, если явно не проверить `IS NULL или IS NOT NULL. • Даже простой фильтр может дать неожиданный результат, если в данных есть пропуски.
💡 Бонус-вопрос:
Что будет, если использовать
NOT department = 'Sales' вместо department <> 'Sales'? 😉Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🔥12❤6🤨2
Forwarded from Machinelearning
https://huggingface.co/learn/llm-course/chapter1/1
Создавайте инструменты с многоэтапным мышлением, используя LangChain и HF.
https://huggingface.co/learn/agents-course/unit0/introduction
Научите агентов принимать решения и учиться на основе окружающей среды.
https://huggingface.co/learn/deep-rl-course/unit0/introduction
Изучите как работает OCR, сегментация и классификация изображений с моделями HuggingFace.
https://huggingface.co/learn/audio-course/chapter0/introduction
Применяйте трансформеры к аудио: распознавание речи, тегирование музыки и синтез речи.
https://huggingface.co/learn/audio-course/chapter0/introduction
Узнайте, как ИИ меняет разработку игр: от поведения NPC до генерации контента.
https://huggingface.co/learn/ml-games-course/unit0/introduction
Работайте с 3D-данными, такими как облака точек и сетки, на стыке графики и ML.
https://huggingface.co/learn/ml-for-3d-course/unit0/introduction
Погрузитесь в технологию, лежащую в основе DALL·E и Stable Diffusion, и научитесь генерировать изображения.
https://huggingface.co/learn/diffusion-course/unit0/1
Коллекция практических ноутбуков от реальных разработчиков ИИ — учитесь, копируйте код и создавайте свои проекты. https://huggingface.co/learn/cookbook/index
@ai_machinelearning_big_data - подписаться
#free #courses #opensource #huggingface
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🔥3👍2💊2🤨1
🧠 SQL-задача с подвохом: “Найди самого активного… по количеству разных друзей”
📘 Условие
У тебя есть таблица дружбы:
Здесь каждая строка означает, что
Записи всегда односторонние: если есть
Нужно написать запрос, который найдёт пользователя с наибольшим числом уникальных друзей.
❓ Пример попытки:
🔍 Вопрос:
1) В чём здесь может быть логическая ошибка?
2) Какую строку подсчитает
3) Когда нужно использовать
4) Как обойти случай, если один и тот же друг записан несколько раз?
✅ Разбор подвоха
💣 Проблема: один пользователь может быть записан как друг **несколько раз**, особенно если приложение допускает дубли (или "перезапросы дружбы").
Пример:
```sql
INSERT INTO friends VALUES (1, 2), (1, 2), (1, 3);
```
В этом случае:
```sql
SELECT COUNT(friend_id) FROM friends WHERE user_id = 1;
-- → вернёт 3
```
Но реальных друзей у пользователя `1` — только **2**: `2` и `3`.
✅ Решение:
Используй `COUNT(DISTINCT friend_id)`:
```sql
SELECT user_id, COUNT(DISTINCT friend_id) AS unique_friends
FROM friends
GROUP BY user_id
ORDER BY unique_friends DESC
LIMIT 1;
```
🎯 Дополнительно можно убрать самого пользователя из списка друзей (на случай ошибок):
```sql
WHERE user_id != friend_id
```
⚠️ Подвох
• `COUNT()` без `DISTINCT` ловит даже опытных — особенно если в БД возможны дубли
• `LIMIT 1` не гарантирует "уникального победителя", если у нескольких одинаковый счёт
• Иногда friendship бывает и симметричной, тогда нужна защита от двойного счёта
📘 Условие
У тебя есть таблица дружбы:
friends(user_id, friend_id)
Здесь каждая строка означает, что
user_id дружит с friend_id. Записи всегда односторонние: если есть
(1, 2), это не значит, что будет (2, 1).Нужно написать запрос, который найдёт пользователя с наибольшим числом уникальных друзей.
❓ Пример попытки:
SELECT user_id, COUNT(friend_id) AS total_friends
FROM friends
GROUP BY user_id
ORDER BY total_friends DESC
LIMIT 1;
🔍 Вопрос:
1) В чём здесь может быть логическая ошибка?
2) Какую строку подсчитает
COUNT(friend_id)? 3) Когда нужно использовать
COUNT(DISTINCT friend_id)? 4) Как обойти случай, если один и тот же друг записан несколько раз?
✅ Разбор подвоха
💣 Проблема: один пользователь может быть записан как друг **несколько раз**, особенно если приложение допускает дубли (или "перезапросы дружбы").
Пример:
```sql
INSERT INTO friends VALUES (1, 2), (1, 2), (1, 3);
```
В этом случае:
```sql
SELECT COUNT(friend_id) FROM friends WHERE user_id = 1;
-- → вернёт 3
```
Но реальных друзей у пользователя `1` — только **2**: `2` и `3`.
✅ Решение:
Используй `COUNT(DISTINCT friend_id)`:
```sql
SELECT user_id, COUNT(DISTINCT friend_id) AS unique_friends
FROM friends
GROUP BY user_id
ORDER BY unique_friends DESC
LIMIT 1;
```
🎯 Дополнительно можно убрать самого пользователя из списка друзей (на случай ошибок):
```sql
WHERE user_id != friend_id
```
⚠️ Подвох
• `COUNT()` без `DISTINCT` ловит даже опытных — особенно если в БД возможны дубли
• `LIMIT 1` не гарантирует "уникального победителя", если у нескольких одинаковый счёт
• Иногда friendship бывает и симметричной, тогда нужна защита от двойного счёта
👀11👍9❤2🔥2💊1
git clone git@github.com:<your-username>/beekeeper-studio.git beekeeper-studio
cd beekeeper-studio/
yarn install
yarn run electron:serve
Beekeeper Studio без проблем работает на всех платформах: Linux, MacOS и Windows
@sqlhub
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍3🔥2🤨2
🧠 SQL-задача с подвохом (Oracle)
Тема: агрегаты, подзапросы, фильтрация без оконных функци
📌 Задача:
Дана таблица
Пример данных:
🧩 Найти:
Выведите отделы, где ЗП всех сотрудников одинаковая, и эту ЗП.
🎯 Подвох:
- многие начинают с
- нужно найти отделы, где MIN(SALARY) = MAX(SALARY), но не забыть, что отдел может содержать одного сотрудника (это корректно)
✅ Ожидаемый результат:
🔍 Решение:
```sql
SELECT DEPT, MIN(SALARY) AS SALARY
FROM EMPLOYEES
GROUP BY DEPT
HAVING MIN(SALARY) = MAX(SALARY);
```
📌 **Пояснение подвоха:**
- `HAVING MIN = MAX` — проверяет, что все значения в группе одинаковые
- Не нужно подзапросов и оконных функций — решение минималистично и эффективно
- Часто используется для поиска «однородных» групп
🧪 Попробуй модифицировать запрос:
• Вывести только те отделы, где **больше одного сотрудника** и ЗП одинаковая
• Или отделы, где все сотрудники получают **разную** ЗП
👍 Лайк, если хотите задачу сложнее
➡ SQL Community
Тема: агрегаты, подзапросы, фильтрация без оконных функци
📌 Задача:
Дана таблица
EMPLOYEES:
CREATE TABLE EMPLOYEES (
ID NUMBER,
DEPT VARCHAR2(50),
SALARY NUMBER
);
Пример данных:
| ID | DEPT | SALARY |
|----|----------|--------|
| 1 | HR | 4000 |
| 2 | HR | 3000 |
| 3 | IT | 5000 |
| 4 | IT | 5000 |
| 5 | Finance | 6000 |
| 6 | Finance | 5500 |🧩 Найти:
Выведите отделы, где ЗП всех сотрудников одинаковая, и эту ЗП.
🎯 Подвох:
- многие начинают с
GROUP BY DEPT, но обычный AVG или SUM не помогут- нужно найти отделы, где MIN(SALARY) = MAX(SALARY), но не забыть, что отдел может содержать одного сотрудника (это корректно)
✅ Ожидаемый результат:
| DEPT | SALARY |
|---------|--------|
| IT | 5000 |🔍 Решение:
`
SELECT DEPT, MIN(SALARY) AS SALARY
FROM EMPLOYEES
GROUP BY DEPT
HAVING MIN(SALARY) = MAX(SALARY);
```
📌 **Пояснение подвоха:**
- `HAVING MIN = MAX` — проверяет, что все значения в группе одинаковые
- Не нужно подзапросов и оконных функций — решение минималистично и эффективно
- Часто используется для поиска «однородных» групп
🧪 Попробуй модифицировать запрос:
• Вывести только те отделы, где **больше одного сотрудника** и ЗП одинаковая
• Или отделы, где все сотрудники получают **разную** ЗП
Please open Telegram to view this post
VIEW IN TELEGRAM
❤28👍15🔥5🤨2
🧠 SQL-задача: "Самая длинная непрерывная сессия"
Условие:
Есть таблица логинов пользователей:
Нужно — для каждого пользователя найти его максимальную по длине цепочку непрерывных ежедневных входов.
Если он заходил 1, 2, 3, 5 и 6 января — самая длинная последовательность без пропусков: 3 дня (1–3 января).
Учитываются только уникальные дни входа (то есть даже если зашёл 3 раза в день — это один день).
Ожидаемый результат:
Решение основано на классической технике: «группировка по смещению».
Шаги:
1. Убираем дубликаты по датам
2. Пронумеровываем строки по `ROW_NUMBER` для каждой даты входа
3. Вычисляем разницу между датой и порядковым номером — она будет **одинакова для цепочки подряд идущих дат**
4. Группируем по этой разности и ищем максимальную длину цепи
Решение (PostgreSQL):
```sql
WITH distinct_dates AS (
SELECT DISTINCT user_id, DATE(login_time) AS login_date
FROM user_logins
),
numbered AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM distinct_dates
),
grouped AS (
SELECT *,
login_date - INTERVAL '1 day' * rn AS grp
FROM numbered
),
grouped_ranges AS (
SELECT user_id,
MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS chain_length
FROM grouped
GROUP BY user_id, grp
)
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY chain_length DESC) AS rnk
FROM grouped_ranges
) final
WHERE rnk = 1;
```
Как работает:
- `ROW_NUMBER` генерирует позицию в порядке дат
- Вычитание `login_date - rn` создаёт искусственный "ключ", по которому мы группируем
- Внутри группы — последовательные даты
- Выбираем цепочку с максимальной длиной по каждому `user_id`
Почему это задача с подвохом:
• Нельзя решить через простой
• Требуется умение работать с датами, оконными функциями и многоступенчатыми CTE
• Это реальный кейс из аналитики поведения пользователей, встречается в проде
➡ SQL Community
Условие:
Есть таблица логинов пользователей:
CREATE TABLE user_logins (
user_id INT,
login_time TIMESTAMP
);
Нужно — для каждого пользователя найти его максимальную по длине цепочку непрерывных ежедневных входов.
Если он заходил 1, 2, 3, 5 и 6 января — самая длинная последовательность без пропусков: 3 дня (1–3 января).
Учитываются только уникальные дни входа (то есть даже если зашёл 3 раза в день — это один день).
Ожидаемый результат:
| user_id | start_date | end_date | chain_length |
|---------|------------|------------|--------------|
| 101 | 2024-01-01 | 2024-01-03 | 3 |
| 102 | 2024-03-05 | 2024-03-09 | 5 |Решение основано на классической технике: «группировка по смещению».
1. Убираем дубликаты по датам
2. Пронумеровываем строки по `ROW_NUMBER` для каждой даты входа
3. Вычисляем разницу между датой и порядковым номером — она будет **одинакова для цепочки подряд идущих дат**
4. Группируем по этой разности и ищем максимальную длину цепи
Решение (PostgreSQL):
```sql
WITH distinct_dates AS (
SELECT DISTINCT user_id, DATE(login_time) AS login_date
FROM user_logins
),
numbered AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM distinct_dates
),
grouped AS (
SELECT *,
login_date - INTERVAL '1 day' * rn AS grp
FROM numbered
),
grouped_ranges AS (
SELECT user_id,
MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS chain_length
FROM grouped
GROUP BY user_id, grp
)
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY chain_length DESC) AS rnk
FROM grouped_ranges
) final
WHERE rnk = 1;
```
Как работает:
- `ROW_NUMBER` генерирует позицию в порядке дат
- Вычитание `login_date - rn` создаёт искусственный "ключ", по которому мы группируем
- Внутри группы — последовательные даты
- Выбираем цепочку с максимальной длиной по каждому `user_id`
Почему это задача с подвохом:
• Нельзя решить через простой
GROUP BY • Требуется умение работать с датами, оконными функциями и многоступенчатыми CTE
• Это реальный кейс из аналитики поведения пользователей, встречается в проде
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍7❤5🤨2💊2
🧠 8 полезных советов по Oracle SQL
Если ты уже «умеешь в SELECT», пора прокачать SQL в Oracle до следующего уровня. Эти советы не для новичков — они для тех, кто работает с продом, сложными запросами и оптимизацией.
⚡ 1. Используй `PIVOT`/`UNPIVOT` вместо `CASE`
Поворот таблиц через
🧱 2. Вызывай функции как таблицы (`TABLE()` + PL/SQL)
Если функция возвращает коллекцию, её можно SELECT’ить напрямую:
🚀 3. Генерация чисел без тормозов
🔍 4. Помогай оптимизатору через `CARDINALITY` hint
Oracle может ошибаться в оценке количества строк. Подскажи ему:
🧠 5. Используй `RESULT_CACHE` для повторяемых данных
Снизь нагрузку:
📉 6. Никогда не делай `ORDER BY` без `FETCH FIRST` или `ROWNUM`
Не сортируй всё зря:
📦 7. Управляй CTE через `MATERIALIZE` и `INLINE`
Это может влиять на производительность:
📊 8. Освой `MODEL` для расчётов как в Excel
Рядовые и прогнозные расчёты в SQL без курсоров:
💡 Не ограничивайся SELECT — используй весь потенциал Oracle SQL.
👍 Лайк и сохраняй себе, чтобы не потерять
➡ SQL Community | Чат
Если ты уже «умеешь в SELECT», пора прокачать SQL в Oracle до следующего уровня. Эти советы не для новичков — они для тех, кто работает с продом, сложными запросами и оптимизацией.
⚡ 1. Используй `PIVOT`/`UNPIVOT` вместо `CASE`
Поворот таблиц через
PIVOT делает код чище и легче масштабируется.
SELECT * FROM (
SELECT department_id, gender, salary FROM employees
)
PIVOT (
SUM(salary) FOR gender IN ('M' AS male_salary, 'F' AS female_salary)
);
🧱 2. Вызывай функции как таблицы (`TABLE()` + PL/SQL)
Если функция возвращает коллекцию, её можно SELECT’ить напрямую:
SELECT * FROM TABLE(my_package.get_active_users(SYSDATE));
🚀 3. Генерация чисел без тормозов
CONNECT BY LEVEL — это медленно. Лучше так:
SELECT rownum FROM dual CONNECT BY rownum <= 10000;
🔍 4. Помогай оптимизатору через `CARDINALITY` hint
Oracle может ошибаться в оценке количества строк. Подскажи ему:
SELECT /*+ cardinality(e 100000) */ * FROM employees e ...
🧠 5. Используй `RESULT_CACHE` для повторяемых данных
Снизь нагрузку:
SELECT /*+ RESULT_CACHE */ * FROM country_codes;
📉 6. Никогда не делай `ORDER BY` без `FETCH FIRST` или `ROWNUM`
Не сортируй всё зря:
SELECT * FROM employees ORDER BY salary DESC FETCH FIRST 10 ROWS ONLY;
📦 7. Управляй CTE через `MATERIALIZE` и `INLINE`
Это может влиять на производительность:
WITH /*+ MATERIALIZE */ heavy_part AS (...)
SELECT * FROM heavy_part WHERE rownum = 1;
📊 8. Освой `MODEL` для расчётов как в Excel
Рядовые и прогнозные расчёты в SQL без курсоров:
SELECT * FROM sales
MODEL
PARTITION BY (region)
DIMENSION BY (month)
MEASURES (sales)
RULES (
sales[13] = sales[12] * 1.1
);
💡 Не ограничивайся SELECT — используй весь потенциал Oracle SQL.
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍13❤4🤔2💊2🔥1🤨1
🧩 SQL-задача с подвохом (Oracle): рейтинг клиентов по заказам
У тебя есть таблица заказов:
Данные:
🎯 Задача:
Напиши SQL-запрос, который для каждого
• сумму всех заказов (`SUM(amount)`) — учитывай только строки, где
• количество заказов (включая `NULL`-значения)
• рейтинг клиента (`RANK()`), где самый высокий
• если у клиента
⚠️ Подвох:
Oracle по умолчанию сортирует
💡 Ожидаемый результат:
✅ Решение:
```sql
SELECT
customer_id,
SUM(amount) AS sum_amount,
COUNT(*) AS order_count,
RANK() OVER (
ORDER BY SUM(amount) DESC NULLS LAST
) AS rank
FROM orders
GROUP BY customer_id;
```
🔍 Почему это работает:
• автоматически пропускает , то есть считает только валидные суммы
• считает все строки, даже с
• сортирует по убыванию суммы, а гарантирует, что клиенты без суммы окажутся в конце рейтинга
📌 Вывод:
Даже опытные аналитики иногда забывают, что чувствителен к и что Oracle требует явного указания , чтобы избежать неочевидных ошибок.
➡ SQL Community | Чат
У тебя есть таблица заказов:
CREATE TABLE orders (
order_id NUMBER PRIMARY KEY,
customer_id NUMBER,
amount NUMBER,
order_date DATE
);
Данные:
| order_id | customer_id | amount | order_date |
|----------|-------------|--------|------------|
| 1 | 101 | 500 | 01-JAN-24 |
| 2 | 102 | 300 | 02-JAN-24 |
| 3 | 103 | NULL | 02-JAN-24 |
| 4 | 101 | 700 | 03-JAN-24 |
| 5 | 102 | NULL | 04-JAN-24 |
| 6 | 104 | 400 | 05-JAN-24 |
| 7 | 103 | 200 | NULL |🎯 Задача:
Напиши SQL-запрос, который для каждого
customer_id вернёт:• сумму всех заказов (`SUM(amount)`) — учитывай только строки, где
amount не NULL • количество заказов (включая `NULL`-значения)
• рейтинг клиента (`RANK()`), где самый высокий
SUM(amount) получает ранг 1 • если у клиента
SUM(amount) NULL, он должен получить последний ранг⚠️ Подвох:
Oracle по умолчанию сортирует
NULL в ORDER BY либо вверх, либо вниз в зависимости от ASC или DESC. Это влияет на оконную функцию RANK(). Если не указать NULLS LAST, клиент с NULL в SUM(amount) может получить ранг 1 — что неверно.💡 Ожидаемый результат:
| customer_id | sum_amount | order_count | rank |
|-------------|------------|-------------|------|
| 101 | 1200 | 2 | 1 |
| 104 | 400 | 1 | 2 |
| 102 | 300 | 2 | 3 |
| 103 | 200 | 2 | 4 |
✅ Решение:
```sql
SELECT
customer_id,
SUM(amount) AS sum_amount,
COUNT(*) AS order_count,
RANK() OVER (
ORDER BY SUM(amount) DESC NULLS LAST
) AS rank
FROM orders
GROUP BY customer_id;
```
🔍 Почему это работает:
•
SUM(amount)NULL•
COUNT(*)NULL•
RANK()NULLS LAST📌 Вывод:
Даже опытные аналитики иногда забывают, что
RANK()NULLNULLS LASTPlease open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3🔥2🥱1🤨1
🧠 Хитрая SQL-задача на Oracle: кто не продал — тот тоже в списке
У вас есть таблица
Данные:
🎯 Задача:
Вывести
Но — обязательно включать продавцов, у которых все продажи NULL, и считать, что их сумма равна 0.
---
### ❗ Подвохы:
-
- Нужно сравнивать 0 с
- Надо корректно сгруппировать по региону и учитывать, где NULL'ы не попадают в
---
✅ Решение:
```sql
SELECT s.salesman_id
FROM (
SELECT
salesman_id,
region,
NVL(SUM(amount), 0) AS total_sales
FROM sales
GROUP BY salesman_id, region
) s
JOIN (
SELECT
region,
AVG(amount) AS avg_region_sales
FROM sales
WHERE amount IS NOT NULL
GROUP BY region
) r
ON s.region = r.region
WHERE s.total_sales < r.avg_region_sales;
```
🧠 Разбор:
1. В подзапросе `s`:
- `SUM(amount)` по продавцу → `NULL`, если продаж нет
- `NVL(..., 0)` превращает такие NULL в 0
2. В подзапросе `r`:
- `AVG(amount)` по региону, игнорируя NULL
- Только валидные продажи участвуют в средней
3. Сравниваем: **продавцы с 0 продаж тоже идут в сравнение**
💡 Вывод:
Этот запрос:
- корректно считает продажи даже для "нулевых" продавцов
- использует `NVL()` и фильтрацию `WHERE amount IS NOT NULL`
- демонстрирует знание поведения агрегатных функций и подзапросов
👀 На собеседованиях часто забывают, что `SUM(NULL)` даёт `NULL`, и сравнение с `AVG` не срабатывает без `NVL`.
➡ SQL Community | Чат
У вас есть таблица
sales:
CREATE TABLE sales (
salesman_id NUMBER,
region VARCHAR2(50),
amount NUMBER
);
Данные:
| salesman_id | region | amount |
|-------------|------------|--------|
| 101 | 'North' | 200 |
| 101 | 'North' | NULL |
| 102 | 'North' | 150 |
| 103 | 'North' | NULL |
| 104 | 'South' | 300 |
| 105 | 'South' | NULL |
🎯 Задача:
Вывести
salesman_id тех продавцов, чья сумма продаж в своём регионе меньше средней по региону, учитывая только те записи, где `amount` не NULL. Но — обязательно включать продавцов, у которых все продажи NULL, и считать, что их сумма равна 0.
---
### ❗ Подвохы:
-
SUM() и AVG() игнорируют NULL, но если у человека *все* значения NULL, SUM вернёт NULL.- Нужно сравнивать 0 с
AVG, а не NULL.- Надо корректно сгруппировать по региону и учитывать, где NULL'ы не попадают в
AVG.---
✅ Решение:
```sql
SELECT s.salesman_id
FROM (
SELECT
salesman_id,
region,
NVL(SUM(amount), 0) AS total_sales
FROM sales
GROUP BY salesman_id, region
) s
JOIN (
SELECT
region,
AVG(amount) AS avg_region_sales
FROM sales
WHERE amount IS NOT NULL
GROUP BY region
) r
ON s.region = r.region
WHERE s.total_sales < r.avg_region_sales;
```
🧠 Разбор:
1. В подзапросе `s`:
- `SUM(amount)` по продавцу → `NULL`, если продаж нет
- `NVL(..., 0)` превращает такие NULL в 0
2. В подзапросе `r`:
- `AVG(amount)` по региону, игнорируя NULL
- Только валидные продажи участвуют в средней
3. Сравниваем: **продавцы с 0 продаж тоже идут в сравнение**
💡 Вывод:
Этот запрос:
- корректно считает продажи даже для "нулевых" продавцов
- использует `NVL()` и фильтрацию `WHERE amount IS NOT NULL`
- демонстрирует знание поведения агрегатных функций и подзапросов
👀 На собеседованиях часто забывают, что `SUM(NULL)` даёт `NULL`, и сравнение с `AVG` не срабатывает без `NVL`.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🥱3❤2🔥1🤨1
🔥 Polars: шпаргалка
Polars ≠ Pandas. Это колоночный движок, вдохновлённый Rust и SQL. Никаких
🚀 Быстрый старт
📊 Выборка и фильтрация
• Комбинированные условия:
---
## ⚙️ Трансформации
• Вычисление новых колонок:
• Удаление/переименование:
•
🧠 Группировка и агрегаты
• Агрегация с кастомной функцией:
---
## 🪄 Ленивая обработка (LazyFrame)
✅ Всё оптимизируется *до выполнения* — pushdown, predicate folding, projection pruning.
🔥 Joins
Варианты:
📂 Работа с файлами
Ленивая загрузка:
---
## 🧮 Аналитика и окна
🧱 Структуры, списки, explode
• Работа с вложенными списками:
🧪 Полезные фичи
• Проверка типов:
• Проверка на null:
• Заполнение:
• Выбор n лучших:
📦 Советы и best practices
• Используй
• Избегай
• Сохраняй
•
✅ Polars: минимализм, скорость, безопасность.
Polars ≠ Pandas. Это колоночный движок, вдохновлённый Rust и SQL. Никаких
SettingWithCopyWarning — всё иммутабельно и параллелится.🚀 Быстрый старт
import polars as pl
df = pl.DataFrame({
"id": [1, 2, 3],
"name": ["Alice", "Bob", "Charlie"],
"score": [95, 85, 100]
})
📊 Выборка и фильтрация
df.filter(pl.col("score") > 90)
df.select(pl.col("name").str.lengths())
df[df["id"] == 2]
• Комбинированные условия:
df.filter((pl.col("score") > 80) & (pl.col("name").str.contains("A")))
---
## ⚙️ Трансформации
• Вычисление новых колонок:
df.with_columns([
(pl.col("score") / 100).alias("percent"),
pl.col("name").str.to_uppercase().alias("name_upper")
])
• Удаление/переименование:
df.drop("id").rename({"name": "username"})
•
apply() — только если нельзя обойтись иначе:
df.with_columns(
pl.col("score").map_elements(lambda x: x * 2).alias("doubled")
)
🧠 Группировка и агрегаты
df.groupby("name").agg([
pl.col("score").mean().alias("avg_score"),
pl.count()
])
• Агрегация с кастомной функцией:
df.groupby("name").agg(
(pl.col("score") ** 2).mean().sqrt().alias("rms")
)
---
## 🪄 Ленивая обработка (LazyFrame)
lf = df.lazy()
result = (
lf
.filter(pl.col("score") > 90)
.with_columns(pl.col("score").log().alias("log_score"))
.sort("log_score", descending=True)
.collect()
)
✅ Всё оптимизируется *до выполнения* — pushdown, predicate folding, projection pruning.
🔥 Joins
df1.join(df2, on="id", how="inner")
Варианты:
"inner", "left", "outer", "cross", "semi", "anti"📂 Работа с файлами
pl.read_csv("data.csv")
df.write_parquet("out.parquet")
pl.read_json("file.json", json_lines=True)
Ленивая загрузка:
pl.read_parquet("big.parquet", use_pyarrow=True).lazy()
---
## 🧮 Аналитика и окна
df.with_columns([
pl.col("score").rank("dense").over("group").alias("rank"),
pl.col("score").mean().over("group").alias("group_avg")
])
🧱 Структуры, списки, explode
df = pl.DataFrame({
"id": [1, 2],
"tags": [["a", "b"], ["c"]]
})
df.explode("tags")
• Работа с вложенными списками:
df.select(pl.col("tags").list.lengths())
🧪 Полезные фичи
• Проверка типов:
df.schema
df.dtypes
• Проверка на null:
df.filter(pl.col("score").is_null())
• Заполнение:
df.fill_null("forward")
• Выбор n лучших:
df.sort("score", descending=True).head(5)
📦 Советы и best practices
• Используй
lazy() для производительности.• Избегай
.apply() — если можешь, используй pl.col().map_elements() или векторные выражения.• Сохраняй
schema — удобно при пайплайнах данных.•
@pl.api.register_expr_namespace("yourns") — добавляй кастомные методы как namespace.✅ Polars: минимализм, скорость, безопасность.
❤12👍5🔥4🥱1