Модераторы: LSD
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Помогите составить запрос! 
:(
    Опции темы
SID_M
Дата 30.4.2005, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 195
Регистрация: 11.2.2005
Где: Россия, г. Москва

Репутация: нет
Всего: нет



Народ, мастера SQL! Помогите запросик составить...
Есть две таблицы
Documents(ID, Name, ...)
|___________
|
DocumentClassifyers(ID, DocID, ClassifyerID, ...)
Есть еще список, состоящий из ClassifyerID...

Смысл понятен? Есть документ и у него может быть куча классификаторов. Нужно сделать выборку по списку классификаторов. Т.е. вывести документы у которых есть все классификаторы из списка...
В реляционной алгебре для такого дела есть оператор деления, а вот как это дело написать на SQL?

Добавлено @ 11:33
Вот блин, пробелы пропускаются...
В общем связь Documents.ID -> DocumentClassifyers.DocID

А база данных MSAccess...
--------------------
Если тебе не дано летать, то хотя бы ползай с гордо поднятой головой.
PM MAIL ICQ Skype GTalk   Вверх
Stampede
Дата 2.5.2005, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: нет
Всего: 144



Цитата(SID_M @ 30.4.2005, 11:31)
Есть документ и у него может быть куча классификаторов. Нужно сделать выборку по списку классификаторов. Т.е. вывести документы у которых есть все классификаторы из списка


Это известный подход, когда значения атрибутов хранятся не в виде реляционного отношения, а в виде кучи (heap). Хорош тем, что позволяет добавлять новые атрибуты без изменения структуры таблицы. Запросы, подобные тому, что ты описал, формулируются в виде множественных джойнов к таблице значений (синтаксис для SQL Server):

Код

select Documents.Id from
  Documents d
    join DocumentClassifiers dc1 on d.ID = dc1.DocID and dc1.ClassifyerID = 123
    join DocumentClassifiers dc2 on d.ID = dc2.DocID and dc2.ClassifyerID = 456
    join DocumentClassifiers dc3 on d.ID = dc3.DocID and dc3.ClassifyerID = 789

...

  where dc1.Value = 'Прокладки'
    and dc2.Value = '2005'
    and dc3.Value = 'Верхние Подлипки'


У данной модели есть ряд ограничений (как, например, необходимость приводить значения разных типов к строковому), которые, впрочем, поддаются обходу ценой всяких ухищрений. С точки зрения производительности, при условии использования СУБД с хорошим оптимизатором и на хорошем железе - при средних объемах данных (в пределах миллиона записей в основной таблице) работает вполне приемлемо. Как будет в Access - без понятия.

Успехов smile

PM WWW   Вверх
SID_M
Дата 4.5.2005, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 195
Регистрация: 11.2.2005
Где: Россия, г. Москва

Репутация: нет
Всего: нет



Идея не сработала, но подход красивый! Спасибо! smile
--------------------
Если тебе не дано летать, то хотя бы ползай с гордо поднятой головой.
PM MAIL ICQ Skype GTalk   Вверх
igon
Дата 5.5.2005, 00:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 327
Регистрация: 30.10.2004

Репутация: 3
Всего: 21



Если список, состоящий из ClassifyerID, существует в виде таблицы, скажем, Classifiers, то
Код

Select DocumentID
  From (Select A.ID DocumentID, B.ID ClassifierID
          From Documents A, Classifiers B
        Intersect 
        Select A.ID DocumentID, B.Classifier ClassifierID
          From Documents A, DocumentClassifyers B
          Where a.id = b.id)
  Group By DocumentID
  Having Count(DocumentID) = (Select Count(*)
                                From Classifiers)
Комментарии
Код

Select A.ID DocumentID, B.ID ClassifierID
  From Documents A, Classifiers B 

- это множество всех потенциально правильных комбинаций DocumentID и ClassifierID (обыкновенное "декартово произведение" двух таблиц)
При помощи Intersect (пересечение множеств) отсекаем:
1) несуществующие на данный момент комбинации DocumentID и ClassifierID из "декартова произведения"
2) существующие комбинации DocumentID с "чужим" ClassifierID, т.е. не присутствующим в таблице Classifiers
Из полученного пересечения выбираем те ID документов, в группе которых имеется ровно столько записей, сколько записей в таблице Classifiers.
Проверял на Oracle. Экзотических конструкций вроде нет -> должно работать и на других БД.



--------------------
Хотите поговорить об этом?
PM   Вверх
shilnik
Дата 5.5.2005, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 377
Регистрация: 22.12.2003

Репутация: нет
Всего: 1



Немного перефразирую предыдущий пост

Код

Select DocId
From (SELECT Distinct DocId, ClassifyerID FROM DocumentClassifyers) DC
Group By DocId
Having  Count(ClassifyerID)= (Select Count(*) From Classifyers)




--------------------
каталог товаров qp1
PM MAIL WWW   Вверх
igon
Дата 6.5.2005, 05:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 327
Регистрация: 30.10.2004

Репутация: 3
Всего: 21



to shilnik
К сожалению, перефразировка некорректна smile
В результирующую выборку попадут и документы, у которых КОЛИЧЕСТВО классификаторов (чисто случайно) совпадает с числом записей в Classifiers, но среди них есть "чужие" (см. пункт 2 комментариев). Оно нам надо? smile
А упростить действительно можно:
Код

Select A.ID DocumentID, B.Classifier ClassifierID
          From Documents A, DocumentClassifyers B
          Where a.id = b.id
заменить на
Код

Select B.ID DocumentID, B.Classifier ClassifierID
          From DocumentClassifyers B

(просто очень хотелось упоминаемую в вопросе таблицу Documents куда-нибудь "приткнуть" smile)
Можно и так
Код

Select DocumentID
  From (Select B.ID DocumentID
          From DocumentClassifyers B
          Where B.ClassifierID In (Select D.ID
                                   From Classifiers D)
       )
  Group By DocumentID
  Having Count(DocumentID) = (Select Count(*)
                                From Classifiers)





--------------------
Хотите поговорить об этом?
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Общие вопросы по базам данных"
LSD
Zloxa

Данный форум предназначен для обсуждения вопросов о базах данных не попадающих под тематику других форумов:

  • вопросам по СУБД для которых нет отдельных подфорумов
  • вопросам которые затрагивают несколько разных СУБД (например проблема выбора)
  • инструменты для работы с СУБД
  • вопросы проектирования БД
  • теоретически вопросы о СУБД

Данный форум не предназначен для:

  • вопросов о поиске разлиных БД (если не понимаете чем БД отличается от СУБД то: а) вам не сюда; б) Google в помощь)
  • обсуждения проблем с доступом к СУБД из различных ЯП (для этого есть соответсвующие форумы по каждому ЯП)
  • обсуждения проблем с написание SQL запросов, для этого есть форум Составление SQL-запросов
  • просьб о написании курсовой, реферата и т.п., для этого есть Центр помощи или фриланс биржа
  • объявлений о найме специалистов, для этого есть раздел Объявления о найме специалистов

Если вы не соблюдаете эти правила, не удивляйтесь потом не найдя свою тему/сообщение. ;)


Полезные советы:

При написании сообщения постарайтесь дать теме максимально понятное название. В теме максимально подробно опишите проблему. Если применимо укажите: название базы данных и версии (MySQL 4.1, MS SQL Server 2000 и т.п.); используемых язык программирования; способа доступа (ADO, BDE и т.д.); сообщения об ошибках.

Для вставки кода используйте теги [code=sql] [/code].

Литературу по базам данных можно поискать здесь.

Действия модераторов можно обсудить здесь.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, LSD, Zloxa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | СУБД, общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0517 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.