Консультация № 185696
28.03.2012, 16:01
121.87 руб.
0 10 1
Здравствуйте! У меня возникли сложности с таким вопросом:
Мне надо проверить правильно ли написан запрос и исправить. если неправильно (запускаю в учебной базе Борей MS Access). После запуска идет сообщение - ошибка в части FROM, но я не могу найти.

SELECT Клиенты.Название, Заказы.ДатаРазмещения, Заказы.ДатаНазначения, Поставщики.Название, Товары.Марка, Заказано.Количество
FROM Поставщики LEFT JOIN (Товары INNER JOIN ((Клиенты RIGHT JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента)
INNER JOIN Заказано ON Заказы.КодЗаказа = Заказано.КодЗаказа)
ON Товары.КодТовара = Заказано.КодТовара)
ON Поставщики.КодПоставщика = Товары.КодПоставщика

Обсуждение

Неизвестный
28.03.2012, 17:07
общий
ну со скобками точно нахимичено. а еще нужно определиться, какие данные нужны.

в данном запросе подразумевается полный вывод записей из таблицы Поставщики с присоединением товаров и проч.

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

причем, список клиентов заполнен полностью ( нет такого клиента, на которого оформлен заказ, но его нет в справочнике ) ; в заказе указан код товара, который обязательно присутствует в справочнике товаров; в справочнике поставщиков обязательно есть поставщик, на которого ссылается запись в таблице товаров. это т.н. целостность данных - наличие всех записей в справочниках, на которые есть ссылки в других таблицах.


если я понял правильно, то могу написать исправление в запросе
Неизвестный
28.03.2012, 17:23
общий
SELECT Клиенты.Название, Заказы.ДатаРазмещения, Заказы.ДатаНазначения, Поставщики.Название, Товары.Марка, Заказано.Количество
FROM
(((Клиенты INNER JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента) INNER JOIN Заказано ON Заказы.КодЗаказа = Заказано.КодЗаказа) INNER JOIN Товары ON Товары.КодТовара = Заказано.КодТовара) INNER JOIN Поставщики ON Поставщики.КодПоставщика = Товары.КодПоставщика


как-то так. должно сработать. но только если во всех справочниках есть соответствующие данные. выведет только тех клиентов, у кого есть заказы. если в заказе несколько позиций, то будет несколько записей на одного клиента с одинаковым заказом. еще неизвестно, как учитываются поставщики - если несколько поставщиков поставляют один товар, то как это хранится и какой конкретно поставщик товара учитывается в заказе.

если получилочь - оформлю ответ.
Неизвестный
28.03.2012, 20:51
общий
Я не знаю, что та должно быть. Это такое задание - проверить правильность запроса ( с использованием базы Борей за 2003 год). Я могу приложить методичку - там нет ничего полезного, но в самом конце есть схема базы Борей , там все таблицы.
Прикрепленные файлы:
dc9e5d639a35631179a5ac40a62810c8.pdf
Неизвестный
29.03.2012, 15:00
общий
29.03.2012, 20:21
пост удален для экономии места- полностью перенесен в ответ.
Неизвестный
29.03.2012, 15:06
общий
29.03.2012, 15:17
поставил базу ( Office 2000 ) и проверил запрос.

у меня написало "не поддерживается выражение объединения"
достаточно изменить режим соединения и все получилось.

... FROM Поставщики INNER JOIN ( Товары INNER ...

результат 2169 записей


в этом случае присоединяются только те поставщики, у которых есть поставленные товары для заказов.

кстати, замена на Клиенты INNER JOIN Заказы на результат не повлияло, как я и писал ранее
Неизвестный
29.03.2012, 15:12
общий
я еще часа три на работе и до понедельника меня не будет, поэтому если не будет сообщений в форуме в ближайшее время, оформлю ответ.
Неизвестный
29.03.2012, 17:30
общий
Спасибо. Пишите как Вам удобно по времени.
Неизвестный
29.03.2012, 17:38
общий
хоть заработало? подойдет, если я перенесу большой ответ из мини-форума где расписаны операции соединения? через час будет свободное время составить ответ.
Неизвестный
29.03.2012, 17:55
общий
Да, спасибо, все идет.
Неизвестный
29.03.2012, 20:19
общий
это ответ
Добрый вечер!

Рассмотрим выборку из баз, как преложено в задаче:

FROM Поставщики LEFT JOIN (Товары INNER JOIN ( ( Клиенты RIGHT JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента ) INNER JOIN Заказано ON Заказы.КодЗаказа = Заказано.КодЗаказа ) ON Товары.КодТовара = Заказано.КодТовара ) ON Поставщики.КодПоставщика = Товары.КодПоставщика

Перепишем эту выборку схематично

таблица5 LEFT ( таблица4 INNER ( ( таблица1 RIGHT таблица2 ) INNER таблица3 ) )

Очередность соединения будет соответствовать нумерации таблиц. в таком случае получится

1) таблица1 RIGHT таблица2 = ( Клиенты RIGHT JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента )
Соединяем таблицу клиентов с таблицей заказов, используя RIGHT JOIN, т.е. показывая все записи в таблице заказов, даже если нет соответствия клиента в таблице клиентов. На самом деле здесь можно было использовать INNER JOIN, т.к. справочник клиентов полностью заполнен и ввод данных в таблицу заказов берется из него, а при удалении записи в таблице клиентов идет проверка целостности данных во всех остальных таблицах - в них тоже удаляются все ссылки на этого клиента. Т.к. проверка целостности затрагивает несколько таблиц, то произойдет также удаление записей в таблице Заказано, т.к. в ней имеется ссылка на ключевое поле в таблице Заказ, из которой будут удалятся записи, сответствующие удаляемому клиенту. Поэтому это соединение можно переписать так :
Клиенты INNER JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента
Т.е. показать всех клиентов, у которых есть заказы. Будет отображаться несколько строк с одним клиентом, если у него есть несколько заказов. Написание можно и не исправлять - работает одинаково с INNER и RIGHT ( проверено в базе ) .
Если нужно показать всех клиентов, даже у которых нет заказов, то нужно использовать соединение LEFT :
Клиенты LEFT JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента
Тогда в соответствующих полях будут пустые значения заказа ( вернее значение будет NULL ) .

2) таблица12 INNER таблица3 = ( ( Клиенты RIGHT Заказы ) INNER JOIN Заказано ON Заказы.КодЗаказа = Заказано.КодЗаказа )
Соединением INNER мы показываем, что при подключении содержимого заказа нужно отобразить только те записи, в которых есть заказанные товары, т.е. нет таких, по которым клиент сделал заказ, но не выбрал товар. Все записано правильно и вопросов не возникает.

3) таблица4 INNER таблица123 = ( Товары INNER JOIN ( ( Клиенты RIGHT Заказы ) INNER Заказано ) ON Товары.КодТовара = Заказано.КодТовара )
Здесь тоже вопросов нет. Только если в справочнике товаров нет записи о товаре, который есть в заказе, то такие строки показываться не будут ( но этого быть не должно - справочники заполнены полностью ) . Единственное пожелание - перенести подключение в конец записи для красоты :
((Клиенты RIGHT JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента) INNER JOIN Заказано ON Заказы.КодЗаказа = Заказано.КодЗаказа) INNER JOIN Товары ON Товары.КодТовара = Заказано.КодТовара
, но на правильность соединения это никак не влияет.

4) таблица5 LEFT таблица1234 = Поставщики LEFT JOIN (Товары INNER ( ( Клиенты RIGHT Заказы ) INNER Заказано ) )
ON Поставщики.КодПоставщика = Товары.КодПоставщика
В данном соединении будет выведен весь справочник поставщиков, а если кто-то из них связан с товаром, который есть в заказах, то будут показаны строки всех остальных таблиц. Причем покажется несколько строк с поставщиком на каждый соответствующий товар.
Т.к. неизвестна цель запроса, то нельзя однозначно оценить корректность использования LEFT. Если нужно отобразить только тех поставщиков, которые являются поставщиками товаров в заказе, то однозначно нужно использовать INNER.

Как раз на этом последнем соединении и выводится сообщение "не поддерживается выражение объединения".
Скорее всего, обработчик SQL не может выполнить такое сложное соединение.
Достаточно изменить режим соединения, чтобы все получилось:
... FROM Поставщики INNER JOIN ( Товары INNER ...
результат 2169 записей
В этом случае присоединяются только те поставщики, у которых есть поставленные товары для заказов.

Итого правильным ответом является запрос :

SELECT Клиенты.Название, Заказы.ДатаРазмещения, Заказы.ДатаНазначения, Поставщики.Название, Товары.Марка, Заказано.Количество
FROM Поставщики INNER JOIN ( Товары INNER JOIN ( ( Клиенты RIGHT JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента ) INNER JOIN Заказано ON Заказы.КодЗаказа = Заказано.КодЗаказа ) ON Товары.КодТовара = Заказано.КодТовара ) ON Поставщики.КодПоставщика = Товары.КодПоставщика


Красивее было бы переписать соединение баз немного в другом виде :

FROM ( ( ( Клиенты INNER JOIN Заказы ON Клиенты.КодКлиента = Заказы.КодКлиента ) INNER JOIN Заказано ON Заказы.КодЗаказа = Заказано.КодЗаказа ) INNER JOIN Товары ON Товары.КодТовара = Заказано.КодТовара ) INNER JOIN Поставщики ON Поставщики.КодПоставщика = Товары.КодПоставщика

Так лучше видна очередность и условия подключения баз. Главное не ошибиться с количеством открывающих скобок.



Кстати, можно переделать запрос, чтобы увидеть именно поставщиков, а если по ним есть товары, которые в заказах, то и перечень этих товаров :

SELECT abc.a, abc.b, abc.c, Поставщики.Название, abc.d, abc.e
FROM Поставщики left JOIN
( select Клиенты.Название as a,Заказы.ДатаРазмещения as b,Заказы.ДатаНазначения as c, Товары.Марка as d, Заказано.Количество as e,Товары.КодПоставщика as f
from ((Товары INNER JOIN Заказано ON Товары.КодТовара = Заказано.КодТовара) inner JOIN Заказы ON Заказы.КодЗаказа = Заказано.КодЗаказа) INNER JOIN Клиенты ON Клиенты.КодКлиента = Заказы.КодКлиента
) as abc
ON Поставщики.КодПоставщика = abc.f

Т.к. в тренировочной базе на каждого поставщика имеется хотя бы один какой-либо заказ его товаров, то результатом этого запроса будут все те же 2169 записей. Но если вручную добавить еще одного поставщика, то количество записей увеличится - остальные поля, кроме названия поставщика, будут пустые. Проверил в базе. Это тоже может быть полезно

С уважением.
5
Большое спасибо, очень быстро, правильно и подробно ответили.
Форма ответа