Как отобразить комбинации вещей в реляционную базу данных? - PullRequest
4 голосов
/ 19 мая 2010

У меня есть таблица, записи которой представляют определенные объекты. Для простоты я собираюсь предположить, что таблица имеет только один столбец, и это уникальный ObjectId. Теперь мне нужен способ хранения комбинаций объектов из этой таблицы. Комбинации должны быть уникальными, но могут иметь произвольную длину. Например, если у меня есть ObjectId s

1,2,3,4

Я хочу хранить следующие комбинации:

{1,2}, {1,3,4}, {2,4}, {1,2,3,4}

Заказ не обязателен. Моя текущая реализация состоит в том, чтобы иметь таблицу Combinations, которая отображает ObjectId с CombinationId с. Таким образом, каждая комбинация получает уникальный идентификатор:

ObjectId | CombinationId
------------------------
1        | 1
2        | 1
1        | 2
3        | 2
4        | 2

Это отображение для первых двух комбинаций примера выше. Проблема в том, что запрос на поиск CombinationId определенной комбинации кажется очень сложным. Два основных сценария использования этой таблицы - перебирать все комбинации и извлекать определенную комбинацию. Таблица будет создана один раз и никогда не будет обновляться. Я использую SQLite через JDBC. Есть ли более простой способ или наилучшая практика для реализации такого отображения?

Ответы [ 3 ]

2 голосов
/ 19 мая 2010

Проблема в том, что запрос на поиск CombinationId определенной комбинации кажется очень сложным.

Не должно быть слишком плохо. Если вы хотите, чтобы все комбинации содержали выбранные элементы (с допуском дополнительных элементов), это просто что-то вроде:

SELECT combinationID
FROM Combination
WHERE objectId IN (1, 3, 4)
GROUP BY combinationID
HAVING COUNT(*) = 3 -- The number of items in the combination

Если вам нужна только определенная комбинация (дополнительные предметы не допускаются), она может быть больше похожа на:

SELECT combinationID FROM (
   -- ... query from above goes here, this gives us all with those 3
) AS candidates

-- This bit gives us a row for each item in the candidates, including 
-- the items we know about but also any 'extras'
INNER JOIN combination ON (candidates.combinationID = combination.combinationID)

GROUP BY candidates.combinationID
HAVING COUNT(*) = 3 -- Because we joined back on ALL, ones with extras will have > 3

Вы также можете использовать NOT EXISTS здесь (или в исходном запросе), это, кажется, легче объяснить.

Наконец, вы также можете подумать и иметь один простой запрос

SELECT combinationID
FROM Combination AS candidates
INNER JOIN Combination AS allItems ON 
  (candidates.combinationID = allItems.combinationID)
WHERE candidates.objectId IN (1, 3, 4)
GROUP BY combinationID
HAVING COUNT(*) = 9 -- The number of items in the combination, squared

Другими словами, если мы ищем {1, 2}, и есть комбинация с {1, 2, 3}, мы получим результат {кандидатов, allItems} JOIN из:

{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}

Дополнительные 3 дают COUNT(*), то есть 6 строк после GROUP, а не 4, поэтому мы знаем, что это не та комбинация, которую мы ищем.

1 голос
/ 19 мая 2010

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

CombinationId | Combination
---------------------------
1             | |1|2|
2             | |1|3|4|

Если вы создаете правило, согласно которому вы всегда сортируете ObjectIds при генерации составного значения, легко получить комбинацию для данного набора объектов.

0 голосов
/ 19 мая 2010

Другим вариантом может быть использование реляционных атрибутов, которые в СУБД SQL называются мультимножествами или вложенными таблицами.

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

http://download.oracle.com/docs/cd/B10500_01/appdev.920/a96594/adobjbas.htm#458790

...