NULL++
описание
Канал для тех, кто хочет развиваться как Data Analyst, Data Engineer, BI-Analyst или Data Scientist @HexMikhail
159
подписчиков
Охват к подписчикам
86,2%
ERR
Реакции к просмотрам
5,08%
173 на 25 постов
Пересылки к просмотрам
0,97%
33
Постов в день
0,3
всего 25
Где отзываются чаще
доля реакций к просмотрам- 10:52Привет, аналитики! В прошлый раз мы поговорили о том, чем отличаются DROP, DELETE и TRUNCATE. Знаете какой ещё вопрос задают на собеседованиях? Чем отличаются WHERE и HAVING? Да, обе этих операций фильтруют данные, но они работают на разных этапах запроса. А значит, и понимание порядка выполнения операций - наш главный козырь. Кстати, порядок выполенения тоже иногда спрашивают =) Давайте вспомним, как выполняется запрос: 1. FROM / JOIN -- берем таблицы 2. WHERE -- фильтруем строки ДО группировки 3. GROUP BY -- группируем 4. HAVING -- фильтруем группы ПОСЛЕ группировки 5. SELECT -- выбираем колонки 6. ORDER BY -- сортируем 7. LIMIT / OFFSET -- ограничиваем То есть WHERE: - применяется ещё до группировки (GROUP BY), - фильтрует отдельные строки исходной таблицы, - не может использовать внутри себя агрегаты (SUM, COUNT и т.д.), - а также работает вообще, если в запросе нет группировки (GROUP BY). А вот HAVING: - применяется только после групиировки (GROUP BY), - фильтрует по результатам агрегации, - можно использовать внутри себя агрегаты (SUM, COUNT и т.д.), - и используется только после GROUP BY. Например, возьмём табличку orders. order_id user_id amount status 1 1 100 completed 2 1 200 cancelled 3 2 150 completed 4 2 50 completed 5 3 300 cancelled Задача: Найти пользователей с суммой всех завершённых заказов > 200 SELECT user_id, SUM(amount) as total FROM orders WHERE status = 'completed' -- сначала фильтруем ТОЛЬКО завершенные заказы GROUP BY user_id HAVING SUM(amount) > 200; -- потом фильтруем пользователей с суммой > 200 Логика: - WHERE отсеивает "мусор" (отмененные заказы и т.д), - GROUP BY группирует по пользователям, - HAVING оставляет только тех, кто соответствует критериям по агрегатам. А теперь ещё раз повторим что и когда использовать! WHERE используется для: 1. Фильтрация по конкретным значениям SELECT * FROM users WHERE age > 18; 2. Фильтрация перед группировкой (самый частый случай) SELECT category, AVG(price) as avg_price FROM products WHERE price > 0 -- исключаем товары с ценой 0 GROUP BY category; 3. Фильтрация по связям с другими таблицами SELECT u.* FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.status = 'completed'; -- берем только пользователей с завершенными заказами HAVING используется для: 1. Фильтрация по агрегатам (самый частый случай) SELECT user_id, COUNT(*) as order_count, SUM(amount) as total_spent FROM orders GROUP BY user_id HAVING COUNT(*) >= 5 -- только пользователи с 5+ заказами AND SUM(amount) > 1000; -- которые потратили > 1000 2. Фильтрация после сложных вычислений SELECT YEAR(order_date) as year, MONTH(order_date) as month, AVG(amount) as avg_amount FROM orders GROUP BY YEAR(order_date), MONTH(order_date) HAVING AVG(amount) > (SELECT AVG(amount) FROM orders); -- только месяцы со средним чеком выше общего среднего 3. Фильтрация по нескольким агрегатам SELECT category, MIN(price) as min_price, MAX(price) as max_price, COUNT(*) as count FROM products GROUP BY category HAVING COUNT(*) > 10 AND MAX(price) - MIN(price) < 100; Какие ошибки часто встречаются? 1. Использование HAVING без GROUP BY SELECT COUNT(*) as total FROM orders HAVING COUNT(*) > 10; -- Работает, но бессмысленно, лучше WHERE 2. Использование WHERE с агрегатами SELECT user_id, SUM(amount) as total FROM orders WHERE SUM(amount) > 100 -- ОШИБКА! WHERE не знает про SUM GROUP BY user_id; 3. Использование HAVING с колонкой не из GROUP BY SELECT user_id, SUM(amount) as total FROM orders GROUP BY user_id HAVING status = 'completed'; -- ОШИБКА! status не в GROUP BY и не агрегат Надеюсь, теперь на собеседовании этот вопрос не застанет тебя врасплох 😄 Забирай в заметки и ставь 🔥, если полезно! Попадался вопрос про фильтрацию или порядок выполнения запроса на собесе? 😂 Пиши в комментах @nullpp #собеседования #sql #where #having21,21%
- 11 авг.Привет, аналитики! Сегодня хочу поговорить об одном вопросе, который любят задавать на собеседованиях. Чем отличаются DROP, DELETE и TRUNCATE? Начну с того, что все три команды так или иначе удаляют данные 😁 Но фишка в том, что делают это они по-разному. Поэтому простого ответа "все они удаляют данные" на этот вопрос недостаточно. Давайте разбираться! 1. DELETE — удаляет строки в таблице DELETE FROM users Есть возможность удалять строки по условию, то есть конкретные записи. Например, пользователей с пустым e-mail. DELETE FROM users WHERE email IS NULL Особенности: - Удаление происходит построчно. Да и удалением это назвать не совсем правильно. Строки помечаются как удалённые, но всё равно некоторое время хранятся в таблице. Кстати, при вставке строк INSERT СУБД старается сначала заполнить именно вот такие помеченные строки. - Не освобождает занимаемое место в БД. - Если внутри транзакции, то результат можно откатить через ROLLBACK. - Можно удалить не всё, а лишь определённые строки, использовав WHERE. - Не сбрасывает автоинкремент, если он есть в таблице. - Работает медленно (особенно на больших таблицах), ведь нужно пробежаться по каждой строке, пометить её "удалённой" 2. TRUNCATE — очищает таблицу полностью, сохраняя лишь её структуру (название и типы полей, связи, ограничения и т.д.). Например, почистить таблицу, где хранятся логи: TRUNCATE TABLE logs Особенности: - Удаляет все строки разом. - Нельзя использовать WHERE. - В большинстве СУБД нельзя откатить. - Сбрасывает счётчик автоинкремента. - Работает быстро. - В большинстве СУБД автоматически освобождает место. 3. DROP — удаляет саму таблицу (или базу данных) вместе со структурой. DROP TABLE temp_table Особенности: - Удаляет структуру таблицы. - Нельзя откатить - Удаляет индексы, триггеры, ограничения - всё, что связано с таблицей. - Освобождает место полностью. Поэтому запоминаем раз и на всегда: DELETE — скальпель, удаляем выборочно. TRUNCATE — лопата, вычищаем всё содержимое, оставляя коробку. DROP — бульдозер, сносим коробку вместе с содержимым. P.S. В ClickHouse, например, TRUNCATE работает моментально, даже на терабайтных таблицах. Потому что там нет транзакций в классическом понимании. Надеюсь, теперь на собеседовании этот вопрос не застанет тебя врасплох 😄 Забирай в заметки и ставь 🔥, если полезно! Попадался такой вопрос на собесе? Или может случайно что-то не то удалял? 😂 Пиши в комментах @nullpp #sql #вопрос #собеседование16,25%
- 6 авг.Привет, аналитики! Знаете, когда находишь интересный пост, то сохраняешь его в Избранное, чтобы потом почитать? Мне кажется все так делают. Сохранили и забыли, да?) Разбирал свои закладки в Избранном и наткнулся на давний пост с бесплатным курсом по основам Python на Stepik. Курс называется "Поколение Python". Заглянул по ссылкам - опа! Последнее обновление курса 05.08.2026) Да и отзывы у курса крайне положительные у первой части курса: 5 звёзд из 5 по более чем 25к отзывам! Глянул мельком программу и могу сказать, что это прям основа основ языка. Для кого этот курс написано в нём самом. Данный пост не является рекламой, если что) https://stepik.org/course/58852 - курс для начинающих https://stepik.org/course/68343 - курс для продвинутых Если интересно, то ставь 🔥, чтобы я ещё поковырялся в своём Избранном и может ещё чего интересного нашёл) @nullpp #обучение #python #stepik11,88%
- 3 авг.💻💻💻💻💻 Аналитик данных: кто это и почему ему важно знать SQL Привет! На связи Евгений Буторин, ментор интенсива по SQL 👋🏻 Вам хочется попробовать себя в аналитике, но непонятно, кто такой аналитик на самом деле, что нужно уметь на старте и почему все вокруг твердят именно про SQL? Приходите на мой вебинар — разберём это на реальных примерах и задачах. Разберём: ➖ Кто такой аналитик данных и чем он занимается каждый день на конкретных задачах; ➖ Какие навыки нужны на старте и куда расти дальше — от первого джуна до руководителя отдела; ➖ Порешаем пару реальных SQL-задач вместе и разберём, почему без SQL в аналитике никуда. 🔥 А ещё к нам в гости придёт Михаил Колчар — выпускник Симулейтив, который в 37 лет ушёл из сисадминов в аналитику данных и получил оффер после обучения. Он расскажет свою историю и ответит на любые вопросы прямо в чате! Если присматриваетесь к аналитике или хотите понять, с чего начать, приходите! 📆 4 августа, 19:00 МСК, онлайн ➡️ Ставьте напоминание в календарь, чтобы не забыть! 📈 Симулейтив | 📱 ВК | 📱 YouTube | 📱 Канал о DS9,52%
- 30 июл.Привет, аналитики! Уже больше года прошло с тех пор, как я сменил профессию и устроился работать аналитиком данных. Переобучение давно закончено, дипломы получены. Но я продолжаю посещать различные учебные мероприятия. Почему? В этом посте я попробую объяснить то, что давно вертится у меня в голове, но я не мог подобрать слов, чтобы это описать. По первому диплому я учитель математики и информатики. И я 8+ лет практиковался в этом направлении :) Так вот, в постсоветской педагогике есть такая концепция — ЗУН (знания-умения-навыки), которая сейчас активно применяется в современном образовании. Хорошая или плохая эта концепция — это отдельный длинный разговор. Концепция делит обучение на три этапа: - Что-то узнать теоретически (лекция / параграф в учебнике). - Посмотреть, как теория работает на практике, отработать, закрепить (решение однотипных задач / практика). - Проверить, как усвоились знания (контрольные / тесты / лабораторная работа). У этого подхода есть один большущий минус: в человека пытаются вложить весь объём современных сведений о мире. Но когда я всерьёз занялся самообучением, я понял, что этого метода недостаточно, чтобы развиваться как профессионал. Я пришёл к выводу, что все знания, которые мы получаем, можно разделить на два типа. Первый тип — «тяжёлые» знания. Когда ты садишься и целенаправленно учишься: читаешь теорию, статьи, документацию (или смотришь видео об этом). Затем решаешь задачки, пишешь код, ошибаешься, переписываешь, доводишь до ума — как раз тот самый метод ЗУН. Другими словами - это задачи, которые нужно решать самому. Они прокачивают тебя напрямую. Берёшь реальную проблему, ищешь вариант, исправляешь его — и это остаётся с тобой навсегда. В этом случае ты не забудешь синтаксис, потому что сам три часа мучился с ним в боевом режиме. А есть второй — «лёгкие» знания. Это когда ты просто где-то услышал, увидел, краем уха зацепился. Такой тип называют «насмотренностью» или «наслушенностью». Это задачи, которые достаточно один раз увидеть, как решает кто-то другой. И ты не запоминаешь каждую строчку кода. Ты запоминаешь паттерн, подход, идею: «А так вообще можно было?» И через месяц, когда встречаешь похожую ситуацию, в голове всплывает: «Я где-то это видел, там было примерно так, надо попробовать». И вот второго типа мне как раз и не хватало долгое время. Я понял, что эта наслушенность / насмотренность — она бесценна. Невозможно знать всё. Но можно наслушать про многое. И когда приходит задача, которую ты никогда не решал, мозг достаёт из закромов ту самую случайную фразу с вебинара, конференции или подкаста. И ты уже знаешь, в какую сторону копать. Это, конечно, палка о двух концах. Ты помнишь, что на вебинаре крутой спикер советовал использовать определённый инструмент или подход. Ты внедряешь его в свой проект. А через время понимаешь: он тяжёлый, медленный, да и вообще, как потом оказывается, для других задач. Почему так вышло? Потому что ты слышал идею решения, но не слышал контекст: для каких данных, для какой нагрузки, для какой команды. А без контекста — это просто красивые слова. Но всё это откладывается, и однажды выручает. Но всегда надо держать в голове, что наслушанность создаёт иллюзию простоты. Особенно опасную для новичков. Наслушанность — это про навигацию, а не про карту. Она показывает направление, но не прокладывает маршрут. Знания — это сила. Но только когда ты знаешь, где и как их применить. А наслушанность — это мощный инструмент. Но с ним нужно обращаться аккуратно. А у вас был случай, когда случайное знание помогло решить задачу или спасло проект? Делитесь в комментариях, интересно почитать! @nullpp #размышления #теория #практика #задачи #работа #профессия9,09%
- 5 июн.Привет, аналитики! Первая рабочая неделя на новой работе позади. Ура! Итак... Я устроился в компанию Excite Kit (https://uxrocket.ru/about). Сейчас (на испытательный период) я занимаюсь отчётностью для одного крупного клиента. У них большой переезд из Oracle в ClickHouse (этим занимаюсь не я) и из OracleBI в DataLens (а вот этим как раз занимаюсь я). Более 50 различных отчётов нужно превратить в удобоваримый дашборд (а может и не один). Часть отчётов нужно перенести как есть, а другую часть они будут менять и сейчас формируют для этого ТЗ. Некоторые таблицы там 150+ млн строк. А отчёты содержат джоины по 5-6 таблиц сразу... Вот и надо как-то это ещё и оптимизировать, потому что у DataLens тоже есть свои ограничения как по количеству строк, так и по выделяемой для этого памяти. @nullpp #работа9,09%
- 26 маяПривет, аналитики! Сегодня я расскажу, куда я пропал почти на две недели. Но для начала хочу поздравить себя с Днём рождения! Да-да, именно сегодня оно и есть. А ещё я стал на год опытнее и на несколько седых волос ближе к дата-сайенсу. А теперь к главной теме поста. Мне предложили проверять работы (в том числе и финальные проекты) на курсе «Аналитика данных» в Симулейтив - онлайн-школе, в которой я сам обучался аналитике, благодаря которой я решился пройти этот нелёгкий путь и сменить профессию. Если вы уже являетесь студентом и подошли к финалу своего обучения, то очень вероятно, что именно я буду проверять вашу работу. Уже успешно проверил несколько работ. Я пока не ментор, но, так сказать, эксперт-преподаватель. Есть к чему стремиться. А ещё я проходил всякие собесы и выполнял тестовые задания. Не скажу, что их было прям очень много, но мне хватило. Даже попробовал пробиться в бигтех, ахахаха. В основном после собеса с HR я слышал отказы по причине: "Мы ищем аналитика с опытом от трёх лет", хотя весь мой опыт был указан в резюме изначально. К моему сожалению, конверсия на hh стала ещё меньше, чем год назад, но, несмотря на это, "касаний" с HR было больше. Но вполне возможно, что это связано с тем, что я откликался только на мидловые вакансии. Что из этого получилось, я расскажу через неделю =) #работа #hr @nullpp8,09%
- 12 июл.Привет, аналитики! Интересно, куда я опять пропал? 🤔 А я устроил себе небольшой отпуск в Калининграде. Посмотрел на старинную архитектуру, побывал во многих музеях, да и просто гулял по городу во всех возможных направлениях. Большую часть времени я провёл в самом Калининграде, но также съездили в Зеленоградск — город котиков. Не повезло немного с погодой — попали в самый шторм (который сейчас в Москве, а затем по прогнозам направится в мой родной Архангельск). В Зеленоградске, конечно, совсем всё серьёзно было, а в Калининграде - очень сильный ветер и 12-13 градусов на улице. Но я человек северный — я не замёрз 😁 Что могу ещё сказать: Калининградская область — это очень атмосферно. Будто смесь Европы, советского наследия и морского бриза. Советую обязательно посетить, если ещё не бывали тут. Вообще, в нормальном отпуске не был целый год и очень устал за это время. Но вроде получилось отдохнуть от рутины, и сегодня я отправляюсь в обратный путь. Поездом. Люблю путешествовать поездом, несмотря на то, что обычно от дома до места отдыха поездка занимает около 2х дней. Это мой отдельный вид "медитации". Особенно когда мобильный интернет исчезает часов на 7 (когда едешь по Архангельской области). Читаешь книги, смотришь заранее скаченные сериальчики, спишь — красота! Ах да, ещё есть много времени на "подумать". А вы уже в этом году ездили в отпуск? П.С.: Хотите немного фоток? Тогда ставь 🔥 и я напишу пару постов о том, где побывал и что видел. @nullpp #отпуск #калининград #зеленоградск7,69%
- 1 июн.Привет, аналитики! Ну что ж, пришло время рассказать, что я сегодня работал последний день в Денвик-аналитика, и с завтрашнего для приступаю к работе в другой компании (пока секрет в какой). Сейчас не об этом. За последний месяц я прошёл несколько собесов с HR, пару собесов с директорами и получил один офер. Если подумать, то от первых кликов на hh до офера прошло около 1,5 месяцев. У меня в конце мая планировался небольшой отпуск ко дню рождения, но из-за увольнения, я пошёл навстречу бывшему начальству и отозвал его, чтобы "остаться в хороших отношениях" и закончить текущие проекты. На текущий момент, я понял, что сделал это зря =) В спешном порядке пахал как не в себя, чтобы "не подвести". И... Никакого профита я с этого не поимел, не смотря на то, что закончил все три проекта, которые были у меня в работе в срок и, некоторые, даже раньше на несколько недель. Премию за них мне не начислили, и не начислят. То есть двойной (или даже тройной) профит поимела только компания. Ну что ж? Урок мне на будущее - сразу обговаривать окончательные условия при увольнении =) Спасибо, так сказать, за опыт. Мишезаменителя нашли очень быстро. Ну а почему бы и нет? Количество откликов на вакансии джуна исчисляются сотнями и доходят до тысячи и выше. Насколько мне стало известно, он уже в этот четверг выходит на работу. Ну что ж, удачи ему на этом пути😁 А мне ни пуха, ни пера на новом месте, про которое я расскажу в следующем посте! @nullpp #работа #hr #увольнение7,10%
- 15 июн.Привет, аналитики! Продолжаем разговор про ClickHouse-джойны. В прошлый раз затронул LEFT ANY JOIN, сегодня на очереди LEFT SEMI JOIN. LEFT SEMI JOIN возвращает только строки из левой таблицы, для которых есть хотя бы одно совпадение в правой. При этом возвращается только первое найденное совпадение, декартово произведение не формируется и колонки из правой таблицы не добавляются. -- INNER JOIN (может размножить строки, если справа несколько совпадений) SELECT users.*, orders.amount FROM users INNER JOIN orders ON users.id = orders.user_id; -- LEFT SEMI JOIN (каждый пользователь - максимум один раз, без колонок из orders) SELECT users.* FROM users LEFT SEMI JOIN orders ON users.id = orders.user_id; Важно учитывать, что поведение LEFT SEMI JOIN может зависеть от конкретной СУБД и алгоритма, который использует оптимизатор запросов. В некоторых случаях вместо него могут применяться другие типы соединений или методы оптимизации. Вот ещё примеры: -- Найти пользователей, у которых был хотя бы один заказ SELECT id, name, email FROM users LEFT SEMI JOIN orders ON users.id = orders.user_id; -- Найти курсы, на которые есть хотя бы одна успешная проверка SELECT course_id, course_name FROM courses LEFT SEMI JOIN reviews ON courses.id = reviews.course_id WHERE reviews.status = 'approved'; -- Клиенты с платежами больше 1000₽ SELECT client_id, name FROM clients LEFT SEMI JOIN payments ON clients.id = payments.client_id WHERE payments.amount > 1000; Применять или не применять - дело каждого) И не забываем, что нельзя однозначно сказать, какая из операций будет дешевле - LEFT SEMI JOIN или обычный LEFT JOIN. Это зависит от конкретных условий запроса, характеристик данных и настроек СУБД. Для оценки стоимости, как уже писал ранее, используй инструменты анализа планов запросов (например, EXPLAIN), которые помогут оценить ресурсы, необходимые для выполнения операции. Но обычно SEMI JOIN более эффективен, так как хеш-сет может быть меньше полной хеш-таблицы, а для каждой строки левой таблицы больше не выполняется дополнительное сопоставление. В любом случае, забирай в заметки и ставь 🔥, если полезно.5,69%
- 8 июн.Привет, аналитики! Сегодня без лирики, сразу к делу. Хочу рассказать про одну годную штуку в ClickHouse. Все мы без сомнений любим LEFT JOIN, но всегда есть нюанс: если справа несколько строк — получишь дублирование строк из левой таблицы + соответствующие значения из правой. Классика, всё работает так, как и должно. Но при таком соединении соответствия ищутся и ищутся, пока поиск не дойдёт до конца правой таблицы. А что делать, если я точно уверен, что правая таблица - это справочник, где только уникальные строки? Или мне не нужны все совпадения, а нужно только одно совпадение? В таких случаях можно использовать LEFT ANY JOIN. -- Обычный LEFT JOIN (найдёт все совпадения) SELECT t1.id, t2.value FROM left_table AS t1 LEFT JOIN right_table AS t2 ON t1.id = t2.id; -- ANY LEFT JOIN (возьмёт ПЕРВОЕ попавшееся значение) SELECT t1.id, t2.value FROM left_table AS t1 LEFT ANY JOIN right_table AS t2 ON t1.id = t2.id; Разница колоссальная: LEFT JOIN → 3 строки, если справа 3 записи с одним id. LEFT ANY JOIN → 1 строка на каждый ключ. Берётся первое значение (не детерминировано, нужно быть очень аккуратным, зависит от порядка чтения данных: сортировка на диске, партиции, ORDER BY в запросе, движок таблицы). Или вот ещё пример: SELECT m.name, g.genre FROM movies AS m LEFT ANY JOIN genres AS g ON m.id = g.movie_id; В этом примере для каждой строки из таблицы movies выбирается первая найденная совпадающая строка из таблицы genres. Где полезно? - Быстрые джойны на миллионах строк - Когда тебе всё равно, какое значение подтянется (первые попавшиеся метаданные, например) То есть, LEFT ANY JOIN может быть полезен в сценариях, где точное совпадение не критично, а цель - быстро получить данные без обработки нескольких совпадений. А ещё есть: - LEFT SEMI JOIN - LEFT ANTI JOIN - LEFT ASOF JOIN О них я напишу в следующих постах Ну как, полезно? Забирай в заметки и жми 🔥4,93%
- 16 маяПривет аналитики! Уже неделя прошла после стрима - и ни одного поста за это время! Немного был занят, чуть позже расскажу, это будет интересно =) А пока, хочу рассказать о прикольной штуке в SQL. Есть такая фишка как FILTER - удобная альтернатива CASE WHEN в некоторых случаях. Используется в агрегатных функциях. Например, вместо SUM(CASE WHEN condition THEN 1 END) можно написать COUNT(*) FILTER (WHERE condition) Согласитесь, такой синтаксис легче читается? Поддерживают: PostgreSQL, SQLite (3.30+), DuckDB, ClickHouse Нет в: MySQL, SQL Server, Oracle (там только CASE) Вот ещё пример: -- Продажи по статусу SELECT category, COUNT(*) FILTER (WHERE status = 'completed') AS completed, COUNT(*) FILTER (WHERE status = 'cancelled') AS cancelled FROM orders GROUP BY category; или -- Средний чек только по успешным SELECT AVG(amount) FILTER (WHERE paid_at IS NOT NULL) AS avg_paid FROM transactions; !!! В ClickHouse FILTER (WHERE ...) тоже работает, но есть нюанс. -- count(*) с FILTER не работает SELECT count(*) FILTER (WHERE uid > 2000) FROM users; -- используйте count(1) SELECT count(1) FILTER (WHERE uid > 2000) FROM users; Но вообще, в ClickHouse много всяких дополнительных функций, которые уже решают ряд задач. Например: -- Вместо FILTER SELECT avg(number) FILTER (WHERE number > 50) FROM numbers(100); -- Пишем короче и надёжнее SELECT avgIf(number, number > 50) FROM numbers(100); -- Количество успешных заказов SELECT countIf(1, status = 'completed') FROM orders; -- Сумма только крупных платежей SELECT sumIf(amount, amount > 1000) FROM payments; -- Уникальные пользователи из США SELECT uniqIf(user_id, country = 'US') FROM events; Ну как, полезно? Забирай в заметки и жми 🔥4,85%