Комментарии 14
При расшифровке key\ID значением из таблицы-справочника корректнее использовать left outer join
Да, соглашусь. Но в данном случае INNER JOIN применен для демонстрации того, как отсекается информация, для которой нет совпадений)
Наверное комментарий про left join был к этому коду
SELECT * FROM orders o JOIN prices p ON p.product <> o.product;
Использование оператора <> породит в выборке лишние строки, будут все строки с левой части соединены с одной из правой у которой нет совпадения.
Можно ещё сделать пример соединения с операндом (+) но это же не правильно, даже для обучения самых маленьких.
Правильно:
SELECT * FROM orders o Left JOIN prices p ON p.product = o.product where p.product is null ;
Как мы устали от "это только для демо, в жизни так не бывает".
А в чём собственно проблема у эксперта SQL разобрать реальную ситуацию и показать новичкам правильное применение JOIN, IN, CASE..?
Непредставимо, чтобы трудовик забивал шурупы молотком со словами: это я просто показываю возможности молотка, вообще по гвоздям бить надо, но они чуть дальше лежали, поэтому показываю на шурупах.
Достаточно странно неоднократно видеть в статье:
(o.last_name = 'Петров'
OR o.last_name = 'Коршун')
при наличии в SQL:
o.last_name IN ('Петров', 'Коршун')
Позанудствую. То, что вы пишете, допускается синтаксисом SQL, но, формально, все что не a = b AND c = d AND foo = bar AND ...
(причем все a
, b
, и т.д. должны быть при этом именно столбцами таблиц) с точки зрения реляционной теории (да и с точки зрения планировщика запросов) JOIN-ом не является. Если вы пишете для новичков, то, имхо, стоило бы об этом упомянуть.
Странная статья. Поставил минус с комментарием "ничего не понял".
Во-первых, я бы поменял заголовок, потому что под этим читатель действительно ждет рифмы "inner" и "outer". Если речь только про дополнительные условия в ON, то так и надо написать в заголовке.
Плюс непонятно, куда делись фонари во втором эксперименте. Ведь подопытные их вроде не покупали?
Ну и CASE тут явно притянут за уши. Вот прямо серьезно, case с подзапросами на два экрана? И не используем мы его только потому что "медленнее", а не потому что он тут не пришей кобыле хвост?
В эксперименте 1 постановка задачи не соответствует решению.
В постановке - найти товары, которые никогда не покупались двумя покупателями, в решении - товары, которые покупались не этими двумя покупателями.
Для самых маленьких.
Не включает описание JOIN между различными типами таблиц. Например, соединение между обычной таблицей и временной (с решёткой у MS SQL (aka #ProductSegment) или temp table у Postgres) или между обычной, и табличной переменной (@temptable) А ведь когда используются различные типы таблиц можно получить значительную задержку, потому что оптимизатор запросов триггернулся на табличную переменную или времянку. Ещё самое интересное, когда оптимизатор меняет план запроса из-за нового порядка соединений. Т.е. порядок таблиц, которые джойнятся важен.
Запрос в эксперименте 2 вернёт не то: если Петров и Коршун вообще ничего не покупали, то запрос вернёт пустое множество, а необходимо получить все товары. Предикат `NOT EXISTS`, можно сказать, является "дословным переводом" условия и решает задачу, а попытки собрать это же из джоина как минимум запутают. А по теме: если при обучении SQL заранее не закладывать в голову условность про равенство, а сразу использовать термины "предикат" или "условие" (которое может быть любым, лишь бы давало в результате True/False), как это делается в документации к большинству СУБД, то и проблема решается сама собой.
Условие в последнем JOIN "потеряет" данные на максимальных значениях price для каждой категории, например товар с ценой 10000 будет попросту отсечён, т.к. он больше либо равен 0 и НЕ меньше 10000(к слову, о качестве курсов в Яндекс Практикум).JOIN category c ON p.price >= c.limit_1 AND p.price < c.limit_2
Исправить можно переписав на, подходящий сюда, BETWEEN:JOIN category c ON p.price BETWEEN c.limit_1 AND c.limit_2
Так же "потеряются" данные о товарах с ценой выше чем 200000, а тут уже нужен LEFT JOIN и обработка таких случаев в SELECT:CASE WHEN c.category IS NULL THEN 'дорогущий' ELSE c.category END AS category
Про правильное именование хотелось бы добавить:
limit_1 и limit_2 необходимо переименовать в min_price и max_price - вы учите, а нам потом с таким кодом приходится сталкиваться повсеместно. Помимо денег, нужно брать ответственность за качество обучение.
Собеседование пройдено — вас НЕ взяли на работу!
Практика по JOIN в SQL: упрощаем ежедневные задачи и решаем тестовое