#sql #join #db2 #row-number
#sql #Присоединиться #db2 #номер строки
Вопрос:
Student Table
SID Name
1 A
2 B
3 C
Marks Table
id mark subject
1 50 physics
2 40 biology
1 50 chemistry
3 30 mathematics
SELECT distinct(std.id),std.name,m.mark, row_number() over() as rownum FROM
student std JOIN marks m ON std.id=m.id AND m.mark=50
Этот результат повторяется 2 раза даже после использования disticnt . Мой ожидаемый результат будет иметь только один A. если я удалю row_number () вместо() в качестве rownum, он будет работать нормально. Почему это происходит? как решить. Я использую DB2!!
Комментарии:
1. Какой смысл объединять Student и Marks, если вы не хотите получать оценки A как по физике, так и по химии?
2. я просто хочу, чтобы студент, получивший 50 баллов по крайней мере по одному предмету
Ответ №1:
В таблице marks есть две строки с id = 1 и mark = 50.. Таким образом, вы получите две строки в выходных данных для каждой строки в таблице student… Если вам нужна только одна, вам нужно создать группу по
SELECT std.id, std.name, m.mark, row_number()
over() as rownum
FROM student std
JOIN marks m
ON m.id=std.id AND m.mark=50
Group By std.id, std.name, m.mark
Комментарии:
1. ВСЕГДА помещайте предикаты объединения в соединение. Предикаты предложения Where не вычисляются до тех пор, пока не будет сгенерирован весь результирующий набор, поэтому ненужные строки переносятся на протяжении всей обработки, и в некоторых сценариях внешнего соединения помещение предикатов в предложение where приведет к получению неверных результатов. Наконец, помещение предикатов join в join помещает их рядом с таблицами, о которых они говорят, а не все вместе в конце, что добавляет ясности запросу.
2. КРОМЕ того, иногда требуется присоединиться к одной и той же таблице более одного раза, используя РАЗНЫЕ предикаты для каждого объединения. Как вы собираетесь это сделать в предложении Where?
3. @CharlesBretana Каждая крупная реляционная база данных достаточно умна, чтобы ставить условия фильтрации перед
JOIN
условиями при фактической оценке запроса; они довольно хороши в сокращении количества операций, которые они должны выполнять (иначе говоря, оптимизация). Вообще говоря, добавляете ли вы что-то подобноеm.mark = 50
вWHERE
илиON
предложение, даже не влияет на план запроса. Таким образом, эстетическое улучшение является единственным реальным соображением (по крайней мере, для внутренних объединений), и включение таких условий вWHERE
предложение намного более интуитивно.4. НЕТ, это не так, потому что результаты помещения предиката в каждое из этих двух мест отличаются (или могут отличаться), и оптимизатор не может быть сконструирован так, чтобы читать мысли автора запроса. В одном случае предикат вычисляется до объединения, а в другом случае он вычисляется после объединения.
5. @CharlesBretana Результаты могут отличаться только для не
INNER
объединений, к которым запрос в вашем ответе не относится. Попробуйте это в обоих местах вашей любимой базы данных и проверьте, отличаются ли планы запросов. Их не будет. Подобная перестановка шагов является основной частью оптимизации. И фактически, для не-INNER
объединений включение фильтра вON
предложение замедляет выполнение запроса, поскольку он должен включать больше строк из нефильтрованной таблицы. Да, это другой результирующий набор, но он также редко требуется. Гораздо чаще возникает желание отфильтровать все, что не соответствует фильтру.
Ответ №2:
Теперь, когда вы прояснили свой вопрос как:
Я хочу найти всех студентов с отметкой 50 хотя бы по одному предмету. Я бы использовал запрос:
SELECT student.id, '50'
FROM student
WHERE EXISTS (SELECT 1 FROM marks WHERE marks.id = student.id AND marks.mark = 50)
Это также дает вам гибкость при изменении критериев, например, по крайней мере, одной отметки 50 или меньше.
Комментарии:
1. 1 СУЩЕСТВУЕТ (полусоединение) — это то, что вы действительно хотите сделать. Вам не нужно полное объединение, потому что вам не нужны все эти дополнительные данные. Этот запрос более эффективен по сравнению с выполнением дополнительной работы по полному объединению, а затем выполнением еще большей дополнительной работы по урезанию набора данных только до того, что вы хотели в первую очередь.
2. 1 за использование WHERE EXISTS, но вы забыли о его столбце rownum.
3. @orbfish Я действительно не понимаю, с чем пытается справиться OP
row_number() over ()
. @zod Возможно, вы можете уточнить?4. row_number() over () используется для разбивки на страницы, точно так же, как LIMIT в mysql
5. Чтение
row_number() over ()
этого просто предоставляет последовательный номер строки для каждой строки результирующего набора, так что это, безусловно, могло быть включено. Откуда и ГДЕ важные аспекты решения, но спасибо, что подтолкнули меня к изучению чего-то нового.
Ответ №3:
Аналогично ответу Чарльза, но вы всегда хотите поместить предикат (mark = 50) в предложение WHERE, поэтому вы фильтруете перед объединением. Если это просто домашнее задание, это может не иметь значения, но вы захотите запомнить это, если когда-нибудь столкнетесь с какими-либо реальными данными.
SELECT std.sid,
std.name,
m.mark,
row_number() over() AS rownum
FROM student std
JOIN marks m
ON std.sid=m.id
WHERE m.mark=50
GROUP BY std.sid, std.name, m.mark
Комментарии:
1. Я считаю, что большинство оптимизаторов запросов обычно могут определить наилучшее время для применения фильтров независимо от размещения предложения. Это особенность DB2?
2. @M_M — No — DB2 (по крайней мере, в iSeries), похоже, генерирует одинаковые планы объяснения и, похоже, рассматривает два запроса как эквивалентные (используя одни и те же пути доступа); по крайней мере, для таких простых примеров, как этот. @All — Помещение условия в
WHERE
предложение в отличие отJOIN
предложения не всегда будет возвращать одинаковые результаты (это в основном актуально при использованииLEFT
и / илиEXCEPTION
объединений), поэтому условные выражения следует размещать там, где они будут генерировать правильные результаты, а не из соображений производительности (оптимизатор DB2 тоже довольно хорош).3. @M_M — Я знаком с этим в Oracle. Иногда это выясняет, но иногда выясняется, что вы действительно имеете в виду то, что говорите с SQL, и заканчивается тем, что занимает целую вечность.