Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > СУБД, общие вопросы > Помогите составить запрос!


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

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

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

А база данных MSAccess...

Автор: Stampede 2.5.2005, 20:43
Цитата(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

Автор: SID_M 4.5.2005, 10:00
Идея не сработала, но подход красивый! Спасибо! smile

Автор: igon 5.5.2005, 00:37
Если список, состоящий из 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. Экзотических конструкций вроде нет -> должно работать и на других БД.

Автор: shilnik 5.5.2005, 12:23
Немного перефразирую предыдущий пост

Код

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


Автор: igon 6.5.2005, 05:04
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)



Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)