| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Составление SQL-запросов > SQL. Помощь по запросам для лабораторной работы |
| Автор: JEEN 10.3.2012, 19:51 | ||||||||||
| Язык SQL, какой конкретно - не сказано, но личном мне ближе MySQL. Есть 3 таблицы: KN – книги, KL – клиенты, VD – выдача книг как-то так
я сделал так, но не уверен:
здесь, возможно, union надо использовать?
буду благодарен за любую помощь. |
| Автор: JEEN 11.3.2012, 07:11 |
| неужели никто не знает хотя бы какие функции здесь используются? |
| Автор: JEEN 11.3.2012, 09:43 | ||||||||||||||
Я сам написал первую задачу, только нашел функцию FULL OUTER JOIN по запросу "внешнее соединение sql", почему то думал, что вернет именно null, а не ноль. А вот со второй не могу разобраться, потому что не знаю как из null сделать 0 и наоборот. вот некоторые задачи, которые уже решил Список книг авторов «Иванов», «Петров» и «Андреев», упорядоченный сначала по убыванию по авторам, затем по возрастанию по названиям;
Список клиентов, фамилии которых заканчиваются на «ов»;
Список кодов книг, которые выдавались (без повторов);
Список клиентов, которым выдавались книги с указанием количества выдач;
последний запрос работает, только без указания количества выдач. Пытаюсь сделать так:
но всем книгам присваивается по одной выдаче. Почему так? Список книг, которые не выдавались;
|
| Автор: Zloxa 11.3.2012, 09:57 |
В результате соединения, в случае отсутствия совпадения по критериям соединения, для соединяемых столбцов действительно вернется null. Но только вот количество у вас подсчитывается функцией count, которая не определенного значения не возвращает. Гуглите еще. Внешние соединения бывают трех типов. Впрочем, полное внешнее соединение в этом сулчае, при условии согласованности данных таки решает поставленную задачу. Но его применение все равно для решения задачи в этой постановке - не оправданно. vd.sr может принимать значение null. Фильтруясь по этому критерию вы можете упустить некоторые "выдачи" к тому же фильтроваться вам не надо, вам все равно навдо вывести клиентов, которым ничего не выдавалось. смотрите по чем группируетесь. |
| Автор: JEEN 11.3.2012, 10:02 | ||||
да это уже просто так поставил, до этого группировал по VD.KK (код клиента), все равно каждому по одному ставит. Группировал по книгам, это не удовлетворяет услвию задачи, но хоть не единицы стояли. вот кстати таблица "выдача" ![]()
я видимо вчера не так прочитал задачу, думал "с указанием срока выдачи". Спасибо за замечание |
| Автор: Zloxa 11.3.2012, 10:06 | ||
Ну а теперь смотрите на свои данные, почему должно быть иначе. Только клиенту 3 была выдача более одного раза, но ее вы зачем то отфильтровали по "sr is not null" Ну и опять же, группироватсья по vd.kk - не правильно. Те клиенты, которым не было выдано ни одной книги, попадут в одну группу. |
| Автор: JEEN 11.3.2012, 10:12 | ||||||
точно... невнимательность. Сделал так, теперь все как надо выводит
нам же они вообще не нужны. В условии "клиенты, которым выдавались книги". Или я не так понял опять? |
| Автор: Zloxa 11.3.2012, 10:21 | ||
Где у нас это условие? Я исхожу из условия в топикстарте:
По этому условию нам таки нужны в результате клиенты, которым книги не выдавались. Если же нам не нужны эти клиенты, делать внешнее соединение, а потом, с помощью условия " WHERE VD.KK IS NOT NULL" сводить результат к внутреннему - тоже нелепость. |
| Автор: JEEN 11.3.2012, 10:28 | ||||||||
делаю так:
все точно так же как и в предыдущем случае, но возникает ошибка. Разве cnt нельзя использовать в запросе? цифру 1 я использовал вместо 5 временно, потом поправлю. Добавлено через 1 минуту и 29 секунд
мы немного о разных задачах говорим. я вот про эту:
|
| Автор: Zloxa 11.3.2012, 10:32 | ||
Да, нельзя. Условия where отрабатывают до выполнения группировки, а потому не могут опираться на значения, полученные в ее результате rtfm having Добавлено @ 10:36
Внешнее соединение здесь не уместно. Благодаря условию в where оно деградирует до внутреннего(я об этом уже упоминал), фильтрация по VD.SR постановкой задачи не обусловлена. Добавлено через 8 минут и 18 секунд Вобще, по этой самой причине, чтобы все говорили об одном и том же, обычно на один вопрос открыают один топик. |
| Автор: JEEN 11.3.2012, 10:42 | ||
| Zloxa, огромное спасибо за помощь. Сейчас дошел до сложных задач, попытаюсь еще раз сам сделать, может выйдет что. Список клиентов, бравших книги более 5 раз;
|
| Автор: Zloxa 11.3.2012, 10:48 |
| Замечания все те же 1) эквивалентно внутреннему соединению, внешнее соединение - не уместно 2) При использовании внешнего соединения, в одну группу попадут все клиенты, для которых не было выдач. Вообще запрос работать будет. Но написан он стилистически криво. |
| Автор: JEEN 11.3.2012, 10:59 | ||||
| сейчас напишу что узнал, потом попробую разобраться с замечаниями. в MySQL, как я понял, нет полного внешнего объединения их заменяет левое и правое внешнее объединение (left join, right join), собственно их я и использовал, поэтому запрос для задачи:
будет выглядеть примерно так.
если бы не "значение этого поля должно быть не определено" выходит, что надо использовать не count, а что-то другое? |
| Автор: Zloxa 11.3.2012, 11:09 | ||
Для решения конкретно этой задачи полного внешнего не требуется, а левое оно тоже вполне себе внешнее.
Да, нелепое какое-то условие. Такое ощущение, что оно добавлено преподом от какой то другой задачи. Чтобы выполнит это условие, я бы использовал выражение case, но выглядело бы это как-то кастыльно. |
| Автор: JEEN 11.3.2012, 11:21 | ||||||||
я не понимал разницу между всеми join'ами, поэтому везде исползовал left join. Сейчас прочитал еще раз внимательно, дошло. Запрос еще проще выглядит. фильтрация по VD.SR случайно попала, я просто скопировал со старого решения. на счет группировки аналогично, мне казалось я все испробовал, только VD.KK работало. Сейчас сгруппировал по KL.KK, получилось. В общем, задача:
старое решение
новое решение
|
| Автор: JEEN 11.3.2012, 11:43 | ||||
только функция avg не выдает 0, если книгу не брали.. |
| Автор: Zloxa 11.3.2012, 11:53 | ||||||||
Я именно так и понял, потому и был так настойчив Чисто чтоб закрепить - я как-то http://forum.vingrad.ru/index.php?showtopic=343660&view=findpost&p=2438437. Мне кажется достаточно доходчиво должно бы быть. Осталось одно только замечание. Это будет работать только на MySQL. Стандарт SQL запрещает в списке полей select использовать поля, не перечисленные в group by без применения к ним аггрегатных функций. MySQL единственный из известных мне движков не реализует этого запрета. Разработчики отписываются, мол это для оптимизации, и ограничивают область использования этой фичи в документации. Соответственно, чтобы оторваться от диалекта MySQL вам осталось лишь выдержать это ограничение заменив
на
Добавлено через 4 минуты и 39 секунд
Тут, кстати, тонкий момент. VD.SR может принимать неопределенное значение, и если оно используется, функция avg его не будет использовать при расчете. avg([1,null]) = 1, в то время, как avg([1,0]) = 0.5. Но в постановке задачи этот ньюанс не огооврен, думаю, можно забить(но держать в уме, я бы такой вопрос поднял бы на защите) |
| Автор: JEEN 11.3.2012, 12:48 | ||||||||||||||||||||
хорошие картинки, как-то давно натыкался на подобное, только там круги были. Тогда не сохранил и забыл где видел, а вашу картинку сохранил на комп)
я так понял здесь без разницы что max, что min использовать? лишь бы была какая-то функция?
получилось) только у преподавателя даже нет возможности спросить/проконсультироваться. На дистанционке учусь. вот еще пару запросов сделал, может есть какие-то замечания..
остались 2 задачи, которые никак не получаются.
сделал вот так:
но здесь мешает HAVING COUNT, потому что он считает, что должно быть больше 10 записей, которые брались больше чем на 30 дней. Т.е. сначала выполняется WHERE, отсеивает часть, потом по оставшимся уже проходится HAVING COUNT. А надо как-то, чтобы они вместе работали, например WHERE VD.SR > 30 and count(VD.K) > 10, но тогда GROUP BY мешает.
эм.. тут я даже не представляю как должен вывод выглядеть, речь о 2х разных списках идет. Что-то такого что ли: - Иванов, Петров, Сидоров - Горе от ума (3) - Иванов, Козлов - Евгений Онегин (2) и т.д. разве такой список можно сделать только одним запросом? в общем, я бы, наверное, прошелся по списку книг, у каждой проверял кто ее брал, если ее брали > 1 человека, то выводить ее.. |
| Автор: Zloxa 11.3.2012, 13:33 | ||
тут не знаю. Я пишу на оракле. Оракл не умеет делать жойн для делита. not in или not exists с моей точки зрения выглядило бы как более универсальное решение. C not in - ньюанс: применимо только к not nullable набору данных. Здесь возможна неоднозначность трактовки задачи 1) Книга бралась более 10 раз и всякий раз на срок не менее 30 дней, тогда ваш подход - правильный 2) Книга бралась более 10 раз на общий срок не менее 30 дней, тогда суммируем сроки и отсекаем в havind Мне кажется первый вариант самый близкий к исходной задаче, и вы соврешенно правильно его реализовали. Хотя второй вариант тоже похож на правду. В принципе - то же самое. Группироваться по паре (id_клиент,id_книга) |
| Автор: JEEN 11.3.2012, 14:07 | ||||
у меня серьезные проблемы с пониманием условий %) перечитал 200 раз и до меня дошло, что "Список клиентов, бравших одну и ту же книгу" эту фразу я не так понимаю, думал что нужно найти общие интересы клиентов)) в общем сделал вот так
все работает как надо. Zloxa, спасибо вам огромное. Без вас бы не разобрался. Поставил бы плюсик к каждому посту, но пока 100 сообщений не набрал, нельзя плюсики ставить. |
| Автор: Zloxa 11.3.2012, 14:20 |
Ну и тебе спасибо, что ты не лентяй, не ждал готовых решений, готов был разбираться и думать. Побольше бы таких начинающих. |
| Автор: Zloxa 11.3.2012, 14:56 | ||
Так то это тоже просто. Селфджойн:
получаем список общих интересов |