Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Сложный запрос с внешним присоединением  (Прочитано 19334 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Joiner
Интересующийся

ru
Offline Offline

« : 16-09-2016 15:56 » 

Здравствуйте, уважаемые форумчане!
Есть база с таблицами работ- SetWork, материалов-SetMat и привязки материалов к определенным работам -SetWorkMat. Связь между SetMat и SetWork через SetWorkMat многие-ко-многим. Т.е. для некоторых работ есть материалы и любой материал может использоваться для разных работ. Пример в Access вложен с примером моего запроса.

Суть вопроса такая:
На форме две таблицы - вверху работы, внизу материалы. При переходе по строкам работ внизу должен появиться полный список всех материалов, а в присоединенных столбцах данные из SetWorkMat только для выбранной вверху работы. Пробовал и LEFT JOIN и UNION инструкции, то повторяющиеся записи появляются, то, наоборот часть записей пропадает. Пробовал сложные запросы конструировать, только больше запутался.

* AVSm.rar (52.3 Кб - загружено 848 раз.)
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 17-09-2016 05:06 » 

я бы сделал в БД три таблицы:

1) материалы (uid1, название, описание)
2) работы (uid2, название, реквизиты и тд)
3) материалы для работы (uid1 работы, uid2 материала) ключ(uid1,uid2 )
Записан

Joiner
Интересующийся

ru
Offline Offline

« Ответ #2 : 17-09-2016 06:50 » 

я бы сделал в БД три таблицы:

1) материалы (uid1, название, описание)
2) работы (uid2, название, реквизиты и тд)
3) материалы для работы (uid1 работы, uid2 материала) ключ(uid1,uid2 )

Ну, вообще то, так во вложенном примере базы и сделано. Вопрос стоит в правильном составлении запроса. Нужно сделать запрос, чтобы вывелся ВЕСЬ список материалов БЕЗ ПОВТОРОВ И ПРОПУСКОВ, а в присоединенных столбцах данные материала только для ОДНОЙ работы из связывающей таблицы.
Записан
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 17-09-2016 09:12 » 

а можно структуру таблиц и запросы в студию
а то кое-кто не уимеет access
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Joiner
Интересующийся

ru
Offline Offline

« Ответ #4 : 17-09-2016 09:56 » 

ОК, в сокращенном варианте так:

Поля Работы (Work) - ID_Work(ключ), Name, Union, Price
Поля Материалов (Mat) - ID_Mat(ключ), Name, Union, Price
Связывающая таблица (WorkMat)  - ID_Work(ключ), ID_Mat(ключ), Rashod (Расход материала для конкретной работы)

Связь один-ко-многим Work.ID_Work -> WorkMat.ID_Work
Связь один-ко-многим Mat.ID_Mat -> WorkMat.ID_Mat

Реально в таблице Work и Mat полей больше, но, думаю, это не принципиально. Мне наводка на правильный запрос нужна. С полями, думаю, разберусь. Я пробовал комбинировать и объединение, и присоединение полей, ставил EXISTS, пробовал применять DISTINCT, но у меня либо повторение материала по названию происходит, либо не полный список материалов.

Заранее благодарен.

Добавлено через 2 часа, 55 минут и 1 секунду:
Да, примерный запрос забыл:

Код: (SQL)
SELECT Mat.ID_Mat, Mat.[Name], Mat.[Unit], WorkMat.*
FROM Mat LEFT JOIN WorkMat ON Mat.ID_Mat = WorkMat.ID_Mat
WHERE WorkMat.ID_Work=2 OR WorkMat.ID_Work IS NULL
ORDER BY Mat.[Name];

При таком запросе выводятся не все строки материалов.

Пробовал добавить:

Код: (SQL)
UNION ALL
SELECT Mat.ID_Mat, Mat.[Name], Mat.[Unit]
FROM Mat LEFT JOIN WorkMat ON Mat.ID_Mat = WorkMat.ID_Mat
WHERE WorkMat.ID_Work<>2

Приходится добавлять пустые поля в таблицу Mat? чтобы выровнять, а толку нет - появляются повторяющиеся строки
« Последнее редактирование: 17-09-2016 12:51 от Joiner » Записан
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 17-09-2016 18:45 » 

а это зачем?

OR WorkMat.ID_Work IS NULL


И потом, для понимания

LEFT JOIN WorkMat ON Mat.ID_Mat = WorkMat.ID_Mat
WHERE WorkMat.ID_Work=2

медленно превращается в INNER JOIN

т.е. левое соединение здесь не нужно
Вам нужно получить материалы которые использовались в работе?


Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Joiner
Интересующийся

ru
Offline Offline

« Ответ #6 : 17-09-2016 19:00 » 

Не не так.

OR WorkMat.ID_Work IS NULL - это что бы вывести материалы, которые не привязаны ни к одной работе.
Мне нужно вывести ПОЛНЫЙ список материалов и справа добавить столбцы с расходом только по ОДНОЙ работе. В примере - работа с ключом ID_Work=2. По этой причине и LEFT JOIN.

Для общего понимания это запрос не чтобы получить чего-то. Ну как бы наоборот - для настройки. Нужно настроить привязку материалов к работам. Поэтому и нужен полный список материалов, а добавленные столбцы  - это привязки только к одной работе и поэтому надо видеть привязки только к одной работе.
« Последнее редактирование: 17-09-2016 19:32 от Joiner » Записан
SCRIBE
Гость
« Ответ #7 : 18-10-2016 08:04 » 

А можно немного данных (можно выдуманных, главное структура и повторяемость проблемы), на которых все не так как надо?
Потом изобразить как надо (на картинке, иль еще как).
Это было во первых Отлично
А во вторых,
Код: (SQL)
LEFT JOIN WorkMat ON Mat.ID_Mat = WorkMat.ID_Mat AND WorkMat.ID_Work=2
Описав это условие в Where, вы отрезали материалы которые не подтянулись к этой работе, ибо там не будет WorkMat.ID_Work=2.
И еще, если задвоения все еще есть, значит в работе используется не один материал, уберите подзапросом, или еще как задвоение.
Записан
Joiner
Интересующийся

ru
Offline Offline

« Ответ #8 : 18-10-2016 08:41 » new

Всем спасибо, но задачка давно решилась вот таким запросом

Код: (SQL)
SELECT Mat.[ID_Mat], Mat.[_Name], Mat.[_UnitMat], WM.ID_Work, WM.[_Rashod]
FROM Mat LEFT JOIN
(SELECT * FROM WorkMat WHERE WorkMat.ID_Work=2) AS WM
ON WM.[ID_Mat]=Mat.[ID_Mat]
ORDER BY Mat.[_Name]
Записан
HandKot
Молодой специалист

ru
Offline Offline

« Ответ #9 : 19-10-2016 04:16 » 

Всем спасибо, но задачка давно решилась вот таким запросом

Код: (SQL)
SELECT Mat.[ID_Mat], Mat.[_Name], Mat.[_UnitMat], WM.ID_Work, WM.[_Rashod]
FROM Mat LEFT JOIN
(SELECT * FROM WorkMat WHERE WorkMat.ID_Work=2) AS WM
ON WM.[ID_Mat]=Mat.[ID_Mat]
ORDER BY Mat.[_Name]
Добрый день.
Но данный запрос вернет только материалы для работы с ID=2, а что будете делать с другими работами?
Я вот в ветке Неотложка давал один из вариантов
С другой стороны, если "но задачка давно решилась вот таким запросом", то и ладно. Возможно при постановке задачи Вы не совсем корректно огласили условия
Записан

I Have Nine Lives You Have One Only
THINK!
Joiner
Интересующийся

ru
Offline Offline

« Ответ #10 : 19-10-2016 05:17 » 


Но данный запрос вернет только материалы для работы с ID=2, а что будете делать с другими работами?


Все правильно, если Вы внимательно почитаете стартовый топик. Мне и нужно, чтобы при перемещении по таблице работ, в таблице материалов появлялся расход только для работы на которой стоит курсор.
Записан
HandKot
Молодой специалист

ru
Offline Offline

« Ответ #11 : 19-10-2016 10:24 » 

это-то было понятно. Т.е каждый раз при перемещении по таблице работ, для подчиненной формы Вы будете делать новый запрос, подставляя туда новый ID работы?
При небольших объёмах будет нормально
Записан

I Have Nine Lives You Have One Only
THINK!
Joiner
Интересующийся

ru
Offline Offline

« Ответ #12 : 19-10-2016 10:44 » 

это-то было понятно. Т.е каждый раз при перемещении по таблице работ, для подчиненной формы Вы будете делать новый запрос, подставляя туда новый ID работы?
При небольших объёмах будет нормально


Именно так уже и работает. Записей будет в пределах 1000, думаю тормозить не будет.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines