SQL Portal | Базы Данных – Telegram
SQL Portal | Базы Данных
14.9K subscribers
771 photos
106 videos
43 files
616 links
Присоединяйтесь к нашему каналу и погрузитесь в мир баз данных

Связь: @devmangx

РКН: https://clck.ru/3H4Wo3
Download Telegram
Популярный SQL-вопрос на собеседованиях: Напишите запрос, который находит вторую по величине зарплату в таблице employees. А что делать, если второй по величине зарплаты не существует?

Зачем его задают:

Этот вопрос проверяет не знание синтаксиса, а базовое SQL-мышление. Поиск второй зарплаты заставляет учитывать дубликаты, сортировку, фильтрацию и пограничные случаи вроде «а если значения нет». Он показывает, умеешь ли ты рассуждать о данных, а не просто вытаскивать их запросом.
Интервьюеры также смотрят, понимаешь ли ты, как SQL пошагово обрабатывает результаты, и способен ли писать устойчивые запросы, а не хрупкие. С виду задача простая, но она быстро вскрывает, реально ли человек понимает основы SQL или просто заучил пару шаблонов.

Как отвечать:

Очевидно, способов несколько. Логика простая:

Сначала определить максимальную зарплату.

Затем найти максимальное значение, которое меньше этого максимума.

Для примера возьмём таблицу employees (id, name, salary). В решении ниже используется подзапрос.

Такой подход автоматически корректно работает с дубликатами. Даже если несколько сотрудников получают максимальную зарплату, подзапрос всё равно вернёт одно значение MAX, а внешний запрос найдёт следующую отличающуюся зарплату. Никаких костылей или допущений не нужно.

Самое важное:

Решение с подзапросом надёжное. Если второй по величине зарплаты не существует, запрос спокойно вернёт NULL, а не сломается и не выдаст мусор. Для интервьюера это сигнал, что ты думаешь про edge cases и пишешь защитный SQL.

Решение:

SELECT (
SELECT MAX(salary)
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees)
) AS second_highest_salary;


👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍62
SQL-совет: понимание оператора EXCEPT в SQL

SELECT sales_person, sales_amount
FROM sales
WHERE sales_person = 'Wei Zhang'
OR sales_person = 'Yuki Nakamura'

EXCEPT -- используем EXCEPT, чтобы получить строки из первого запроса, которых нет во втором

SELECT sales_person, sales_amount
FROM sales
WHERE sales_person = 'Wei Zhang'
OR sales_person = 'Giovanni Rossi';


В этом запросе используется оператор EXCEPT для сравнения двух наборов результатов и возврата строк, которые есть в первом SELECT, но отсутствуют во втором.
Первый запрос выбирает записи о продажах, где sales_person равен Wei Zhang или Yuki Nakamura, а второй — записи, где sales_person равен Wei Zhang или Giovanni Rossi.

Так как используется оператор EXCEPT, в итоговый результат попадают только строки, уникальные для первого запроса. В данном случае Yuki Nakamura присутствует в первом наборе результатов, но отсутствует во втором, поэтому его запись включается в финальный вывод.
В то же время Wei Zhang есть в обоих запросах, поэтому соответствующие строки исключаются из итогового результата.

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍133
Операционные накладные расходы: почему целые числа лучше

1. Эволюция схемы

Добавление новых состояний является обычным требованием в развивающихся приложениях. Рассмотрим оперативные этапы для каждого подхода:

Булевы значения:

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

ALTER


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

Целые значения (status):

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

2. Согласованность данных

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

Пример: Для пользователя не должно одновременно выполняться isActive = TRUE и isSuspended = TRUE.

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

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

3. Простые запросы

Запросы по множеству булевых полей сложны и подвержены ошибкам:

-- Множество булевых полей
SELECT * FROM users WHERE isActive = TRUE AND isSuspended = FALSE;


При единственном поле status запросы яснее:

-- Единственное поле status
SELECT * FROM users WHERE status = 1; -- Активный пользователь


В след. посте можем разобрать влияние на запросы клиентов, ставь реакшен 😆

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍63
📱 Держите 6 хороших каналов по искусственному интеллекту и программированию для любого уровня!

Выбирай направление:

📱 Нейросети@neuro_prompt

🤖 AI-инструменты @ai_prompt

📱 Python@python_prompt

🤔 InfoSec & Хакинг @infosec_prompt

👩‍💻 IT Новости @it_news

😄 IT Мемы@it_memes

Промпты, обучение, шпаргалки и полезные ресурсы на каждую тему!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
в Postgres 18 появился новый возвращаемый полеcет для OLD и NEW данных. куча прикладного кода зависит от того чтобы вставить данные и сразу знать старое и новое состояние. теперь можно сразу подтверждать INSERT и UPDATE без лишних костылей.

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥71👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Postgres умеет очень просто агрегировать данные по датам через date_trunc — просто передай day, week, month, quarter и сделай GROUP BY по этому же полю.

SELECT
date_trunc('month', order_date) AS month,
COUNT(*) AS total_orders,
SUM(total_amount) AS monthly_total
FROM
orders
GROUP BY
date_trunc('month', order_date)
ORDER BY
month;


👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍76
This media is not supported in your browser
VIEW IN TELEGRAM
SQL Studio вышел в публичную бету

Современный кроссплатформенный SQL-клиент, сделанный с упором на скорость и простоту.

SQLite уже поддерживается. Остальные диалекты в пути.

Баги прилагаются 🪲

[https://sql.studio]

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3
Почему SQL считается общим языком для работы с данными

SQL настолько важен, что даже внутри Python у тебя всё равно появляется SQL.

Да, даже в pandas — по сути тот же подход.

Да, даже в PySpark — тоже SQL.

Pandas просто заимствовал базовую логику: SELECT, WHERE, GROUP BY, JOIN и завернул её в методы и функции. Синтаксис другой, мышление то же.

Если начать с SQL, потом быстрее въезжаешь в pandas и PySpark — порог входа заметно ниже.

Если уже работаешь с pandas, то выучить SQL тоже будет довольно просто.

Вывод: если ты занимаешься данными, SQL обязателен.

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Копался во внутренностях MySQL и наткнулся на интересную штуку — doublewrite buffer. Это аккуратный хак против порчи данных. Коротко о том, как он работает.

Когда в MySQL (InnoDB) происходит запись, движок не пишет страницу сразу на диск в её финальное место. Вместо этого он делает так:

- сначала пишет страницу в doublewrite buffer на диске
- fsync — чтобы гарантировать, что данные легли
- потом копирует страницу в её финальное место в data file

Зачем этот лишний шаг? Он даёт атомарность и защиту от крэшей.

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

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

Если порча произошла на финальном шаге, InnoDB просто восстанавливает страницу из doublewrite buffer.

Цена — небольшой дополнительный I/O, но выигрыш — высокая надёжность, crash recovery и защита от повреждений. Очень крутое решение с инженерной точки зрения.

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Функции и процедуры на самом деле очень похожи, и многие называют их как попало, но в Postgres это разные вещи.

Functions:

- Считают и возвращают значения
- Не управляют транзакциями
- Можно использовать внутри SELECT или WHERE
- SELECT function()

Procedures:

- Действия и батчи
- COMMIT и ROLLBACK
- Нельзя вызывать внутри SQL
- CALL procedure()

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍112🤔2
Data Modeling

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

Теперь у нас есть таблица с одной строкой на каждую строку файла. Как сгруппировать такие данные? Группировку похожих строк обычно делают через window-функции. В нашем случае нужно «складывать» строки до тех пор, пока не встретится пустая строка, после чего начинать новую группу. Создадим псевдоколонку и будем увеличивать sequence только когда значение в calories_count пустое. Также вызовем setval() для задания начального значения, чтобы функция currval() работала.

CREATE SEQUENCE aoc;
SELECT setval('aoc', 1);
SELECT calories_count,
CASE WHEN calories_count = '' THEN nextval('aoc')
ELSE currval('aoc') END
FROM calories LIMIT 10;


Результат:

calories_count | currval 
---------------+---------
9686 | 1
10178 | 1
3375 | 1
9638 | 1
6318 | 1
4978 | 1
5988 | 1
6712 | 1
| 2
10422 | 2


Как видно, currval меняется, когда sequence обнаруживает новую группу. Используем это свойство, чтобы посчитать сумму по каждой группе. Поскольку у нас текстовый столбец, придется привести его к int перед суммированием. Дополнительно пустая строка не может быть приведена к int, поэтому явно детектируем строку-разделитель и считаем ее значение равным 0.

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Group and Sum

SELECT SUM(calories_count) OVER(partition by currval) FROM
(SELECT CASE WHEN calories_count = '' THEN 0
ELSE calories_count :: int END AS calories_count,
CASE WHEN calories_count = '' THEN nextval('aoc')
ELSE currval('aoc') END
FROM calories
) x LIMIT 10;


Результат:

sum  
-------
56873
56873
56873
56873
56873
56873
56873
56873
43456
43456


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

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
SQL отработал, но цифры не сходятся?

SQL Логи бизнеса — канал про реальные рабочие задачи аналитика

Здесь:
🔸ловушки с собеседований
🔸разборы запросов, которые «работают, но не так как надо»
🔸кейсы из банковской аналитики
🔸тесты

Канал ведёт действующий банковский аналитик с опытом работы в Сбере и Т-Банке и с дипломом ВШЭ

Если вам нужен SQL для работы и собеседований — добро пожаловать в SQL Логи бизнеса

Вот некоторые посты с канала:
Самая частая ошибка джунов
Когда запрос работает, но выдает не то, что вы ожидаете
Когда действительно нужен self-join
4
Дан запрос:

SELECT department, AVG(salary) as avg_salary
FROM employees
WHERE hire_date > '2020-01-01'
GROUP BY department
HAVING AVG(salary) > 60000
ORDER BY avg_salary DESC
LIMIT 5;


Вопрос: какой реальный порядок выполнения?

Варианты:

A) FROM → WHERE → SELECT → GROUP BY → HAVING → ORDER BY → LIMIT
B) FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
C) FROM → WHERE → GROUP BY → SELECT → HAVING → ORDER BY → LIMIT
D) WHERE → FROM → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM