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
Большое спасибо, очень быстро, правильно и подробно ответили.