Отправляет email-рассылки с помощью сервиса Sendsay

RFpro.ru: Базы данных MS SQL

  Все выпуски  

RFpro.ru: Базы данных MS SQL


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты по данной тематике

Коцюрбенко Алексей aka Жерар
Статус: Академик
Рейтинг: 3899
∙ повысить рейтинг »
Абаянцев Юрий Леонидович aka Ayl
Статус: Профессионал
Рейтинг: 2096
∙ повысить рейтинг »
Megaloman
Статус: Академик
Рейтинг: 1788
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Базы данных / MSSQL, Oracle, Interbase, Firebird, FoxPro

Номер выпуска:87
Дата выхода:31.03.2012, 16:30
Администратор рассылки:Филатов Евгений Геннадьевич (Профессионал)
Подписчиков / экспертов:79 / 35
Вопросов / ответов:1 / 1

Консультация # 185696: Здравствуйте! У меня возникли сложности с таким вопросом: Мне надо проверить правильно ли написан запрос и исправить. если неправильно (запускаю в учебной базе Борей MS Access). После запуска идет сообщение - ошибка в части FROM, но я не могу найти. SELECT Клиенты.Название, Заказы.ДатаРазмещения, Заказы.ДатаНазначения, Поставщики.Название...


Консультация # 185696:

Здравствуйте! У меня возникли сложности с таким вопросом:
Мне надо проверить правильно ли написан запрос и исправить. если неправильно (запускаю в учебной базе Борей MS Access). После запуска идет сообщение - ошибка в части FROM, но я не могу найти.

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

Дата отправки: 28.03.2012, 16:01
Вопрос задал: Посетитель - 383373 (Посетитель)
Всего ответов: 1
Страница онлайн-консультации »


Консультирует Филатов Евгений Геннадьевич (Профессионал):

Добрый вечер!

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

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 Поставщики.КодПоставщика = Товары.КодПоставщика
< br>Так лучше видна очередность и условия подключения баз. Главное не ошибиться с количеством открывающих скобок.



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

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 записей. Но если вручную добавить еще одного пост авщика, то количество записей увеличится - остальные поля, кроме названия поставщика, будут пустые. Проверил в базе. Это тоже может быть полезно

С уважением.

Консультировал: Филатов Евгений Геннадьевич (Профессионал)
Дата отправки: 29.03.2012, 20:19

5
Большое спасибо, очень быстро, правильно и подробно ответили.
-----
Дата оценки: 29.03.2012, 20:28

Рейтинг ответа:

НЕ одобряю 0 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка  |  восстановить логин/пароль

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!



В избранное