Как стать автором
Обновить

Практика по JOIN в SQL: упрощаем ежедневные задачи и решаем тестовое

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров24K
Всего голосов 16: ↑8 и ↓8+2
Комментарии14

Комментарии 14

Да, соглашусь. Но в данном случае 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 ('Петров', 'Коршун')

Да, согласен. В данном случае хотелось продемонстрировать все максимально просто. Тех, кто только только начинает, может 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 - вы учите, а нам потом с таким кодом приходится сталкиваться повсеместно. Помимо денег, нужно брать ответственность за качество обучение.

Собеседование пройдено — вас НЕ взяли на работу!

Зарегистрируйтесь на Хабре, чтобы оставить комментарий