SQL - много ко многим альтернативам? - PullRequest
0 голосов
/ 22 января 2019

Предположим, у меня есть записи:

======= =========
Element id
======= =========
        "H"
        "O"

И еще как:

======== ==
Compound id
======== ==
         "Water"

С:

======== == =========== ========== ==========
Relation id compound_id element_id bond
======== == =========== ========== ==========
         1  "Water"     "H"        "Covalent"
         2  "Water"     "H"        "Covalent"
         3  "Water"     "O"        "Covalent"

Теперь, большинство моих запросов не для точного соответствия, но предположим, иногда Я хочу найти соединение с точными элементами = ["H", "H", "O"] (то есть Вода - но не Гидроксид (["H", "O"]) или Пероксид (["H", "H", "O", "O"]).

Как я могу пойти по этому поводу?

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Всегда лучше поддерживать базу данных в норме. В вашем конкретном случае я бы сохранил количество элементов для каждого соединения вместо новой строки для каждого элемента.

 compound_id element_id      bond         count
 -------------------------------------------------
   "Water"     "H"        "Covalent"        2
   "Water"     "O"        "Covalent"        1

Запрос на точное совпадение будет

 select compound_id
 from elements
 group by compound_id
 having count(
              case when 
                (element_id = 'H' and count = 2) or
                (element_id = 'O' and count = 1) then 1 
              end
        ) = count(*)

Однако этот подход будет неоптимальным, поскольку будет использоваться последовательное сканирование. Если денормализация не является проблемой, может помочь хранение нескольких различных элементов для каждого соединения.

 compound_id   element_count
 ------------------------------
   "Water"          2

Тогда запрос может быть

 select e.compound_id
 from elements e
 join compounds c on e.compound_id = c.compound_id
 where c.element_count = 2 and
       ((e.element_id = 'H' and e.count = 2) or
        (e.element_id = 'O' and e.count = 1))
 group by e.compound_id
 having count(*) = 2

и если у вас есть индекс для compounds(element_count) и elements(element_id, count), тогда ваш запрос будет использовать его для быстрого получения результатов, даже если база данных большая.

0 голосов
/ 22 января 2019

Почему бы просто не использовать array_agg()?

select compound_id
from t3
group by compound_id
having array_agg(element_id order by element_id) = array['H', 'H', 'O']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...