惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
IT之家
IT之家
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
P
Palo Alto Networks Blog
Know Your Adversary
Know Your Adversary
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Cisco Talos Blog
Cisco Talos Blog
L
Lohrmann on Cybersecurity
AWS News Blog
AWS News Blog
J
Java Code Geeks
博客园_首页
Scott Helme
Scott Helme
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
T
The Exploit Database - CXSecurity.com
Security Latest
Security Latest
V
Visual Studio Blog
Cloudbric
Cloudbric
Jina AI
Jina AI
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
A
Arctic Wolf
C
Cybersecurity and Infrastructure Security Agency CISA
S
SegmentFault 最新的问题
The Last Watchdog
The Last Watchdog
SecWiki News
SecWiki News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
W
WeLiveSecurity
K
Kaspersky official blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hacker News: Ask HN
Hacker News: Ask HN
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
宝玉的分享
宝玉的分享
Hugging Face - Blog
Hugging Face - Blog
量子位
Google Online Security Blog
Google Online Security Blog
博客园 - Franky
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 三生石上(FineUI控件)
Recent Commits to openclaw:main
Recent Commits to openclaw:main

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
WHERE превращает ваш LEFT JOIN в INNER JOIN. И никто вам об этом не скажет
badcasedaily · 2026-05-26 · via Все публикации подряд на Хабре

Уровень сложностиПростой

Время на прочтение5 мин

Охват и читатели10K

Туториал

Задача знакомая, очень знакомая. Нужна выгрузка: все клиенты и их заказы за апрель. Все — значит все, включая тех, кто за месяц так ничего и не купил. Отсюда LEFT JOIN, а не INNER. Вы это прекрасно знаете, ведь не первый день в SQL.

Пишете запрос. Добавляете WHERE orders.created_at >= '2024-04-01', чтобы отрезать всё, что не апрель. Запускаете.

В таблице клиентов восемь тысяч строк. В выгрузке почему‑то шесть. Две тысячи человек куда‑то испарились. И не абы какие: пропали ровно те, ради кого вы и городили LEFT JOIN — клиенты без заказов.

Неприятнее всего тут не сама пропажа. Неприятнее то, что запрос выглядит безупречно. Вы смотрите на него и не видите ошибки. Её там и нет, в смысле синтаксиса. База не ругнулась, ничего красным не подсветилось. Просто строк меньше, чем нужно, а это глазами не ловится: выгрузка не пустая, шесть тысяч живых записей, всё выглядит настоящим.

Сейчас разберёмся, куда ушли эти две тысячи.

С LEFT JOIN всё в порядке, правда

Снимем подозрение с главного обвиняемого сразу.

LEFT JOIN делает ровно то, что обещает. Берёт каждую строку левой таблицы. Ищет ей пару справа. Нашёл — склеил. Не нашёл, и вот тут самое важное, строку всё равно оставил, просто колонки правой таблицы забил NULL‑ами.

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

То есть LEFT JOIN свою часть выполнил. Все клиенты были на месте. А потом пришёл WHERE.

Запрос читается не так, как выполняется

Мы читаем SQL сверху вниз: сначала SELECT, потом FROM, потом WHERE. И кажется логичным, что выполняется он в том же порядке. Не выполняется.

База сначала берётся за FROM и JOIN. Склеивает таблицы, строит промежуточный результат. И только когда он готов, по нему проходит WHERE и выкидывает ненужные строки.

Все идет к моменту, когда WHERE берётся за дело, LEFT JOIN давно закончил. В промежуточном результате уже лежат наши клиенты без заказов — с честными NULL в колонках orders.

И вот WHERE смотрит на такую строку через своё условие:

SELECT c.id, c.name, o.id AS order_id, o.created_at
FROM clients c
LEFT JOIN orders o ON o.client_id = c.id
WHERE o.created_at >= '2024-04-01';

У клиента без заказов o.created_at — это NULL. И вопрос на сообразительность: NULL >= '2024-04-01' — это правда или ложь?

Ни то ни другое. Это UNKNOWN, «неизвестно», третье значение в логике SQL. Сравнить дату с тем, чего нет, нельзя, вот база и разводит руками.

А WHERE пускает дальше только то, что строго TRUE. UNKNOWN для него — то же самое, что FALSE: на выход. И каждая строка клиента без заказов тихо вылетает.

Что остаётся? Только клиенты с заказом, да ещё подходящим по дате. То есть ровно то, что вернул бы INNER JOIN. Вы написали LEFT, получили INNER, и никто вас не предупредил.

Почему это так легко проглядеть

Синтаксис чистый, оптимизатор доволен. Результат не пустой, в нём тысячи строк, и каждая выглядит как надо. Чтобы заподозрить неладное, нужно заранее знать, сколько строк ты ждёшь, и сверить. А кто это делает каждый раз?

В код‑ревью такое часто пропускается. Коллега видит LEFT JOIN, видит понятный фильтр по дате, ставит апрув. Всё же логично написано.

А отчёт потом не падает, он просто врёт. «Клиентов, которые в апреле ничего не купили, у нас нет», красивый вывод из запроса, где этих клиентов вырезали ещё до того, как кто‑то взялся их считать.

ON и WHERE спрашивают у базы разное

Чинится всё переносом одного условия. Из WHERE — в ON:

SELECT c.id, c.name, o.id AS order_id, o.created_at
FROM clients c
LEFT JOIN orders o
  ON o.client_id = c.id
  AND o.created_at >= '2024-04-01';

С виду — косметика, условие переехало на две строчки выше. На деле поменялось всё.

Условие в ON — это часть правила, по которому ищется пара. Оно отвечает на вопрос «что вообще считать совпадением». Теперь заказ подходит клиенту, только если совпал и по client_id, и по апрелю. У клиента без апрельских заказов пары нет, и LEFT JOIN, как мы уже выяснили, в таком случае оставляет строку с NULL. А WHERE её больше не трогает: фильтра по дате в WHERE теперь просто нет. Клиент остаётся.

Условие в WHERE совсем другое. Это фильтр по уже готовому, склеенному результату. И вопрос здесь другой: «что оставить из того, что получилось». А NULL‑строкам в этом фильтре не выжить, любое сравнение с колонкой правой таблицы их срежет.

Вот и вся разница. ON и WHERE — не два кармана, куда можно сунуть одно и то же условие. Это два разных вопроса. ON спрашивает: что считать парой? WHERE спрашивает: что оставить в конце?

Иногда условие в WHERE — это правильно

Только не уносите отсюда правило «фильтр по правой таблице в WHERE — всегда плохо». Не всегда.

Нужны только клиенты с апрельскими заказами? Пишите INNER JOIN и живите спокойно. Маскировать INNER‑логику под LEFT JOIN с фильтром в WHERE плохо не потому, что не работает — работает. Плохо потому, что следующий человек прочитает LEFT JOIN и поверит ему.

А иногда NULL‑строка в WHERE нужна вам совершенно сознательно. Например, когда надо найти клиентов вообще без заказов:

SELECT c.id, c.name
FROM clients c
LEFT JOIN orders o ON o.client_id = c.id
WHERE o.id IS NULL;

LEFT JOIN притащил всех. WHERE o.id IS NULL оставил только тех, кому пара не нашлась. У всего этого есть имя — антиджойн, способ найти «то, чего нет».

И заметьте: работает он за счёт того же поведения, которое в начале статьи ломало нам выгрузку. LEFT JOIN создаёт NULL‑строки, WHERE умеет по ним фильтровать. Одно и то же свойство — то баг, то фича.

Разница в намерении. В антиджойне вы фильтруете по IS NULL, то есть прямо говорите «лови отсутствие пары». А в сломанном запросе фильтр по дате цепляет NULL‑строку случайно, как побочку, про которую автор и не думал.

Куда же делись две тысячи клиентов

Теперь понятно. LEFT JOIN их не терял — он добросовестно довёл всех до промежуточного результата, с NULL‑ами вместо заказов. Их выкинул WHERE: сравнил NULL с датой, получил UNKNOWN, а UNKNOWN для WHERE — это «не пускать».

С собой унести мысль смотреть на запрос: ON и WHERE задают базе разные вопросы. ON — «что здесь пара?». WHERE — «что оставить, когда всё склеилось?».

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

И каждый раз, встретив в WHERE условие на колонку правой таблицы рядом с LEFT JOIN, вы поймаете себя на мысли: так, а вот тут LEFT только что превратился в INNER.

Кажется, что с SQL всё давно понятно, пока один WHERE внезапно не превращает LEFT JOIN в INNER JOIN. Если хотите проверить, насколько уверенно ориентируетесь в таких нюансах, попробуйте пройти бесплатный тест по SQL для разработчиков и аналитиков.

Если тема SQL и баз данных вам близка, приходите и на бесплатные открытые уроки:

Больше открытых уроков и материалов по backend, SQL и инфраструктуре публикуем на канале OTUS в MAX.