MySQL - лучший подход для обеспечения уникальных значений в нескольких строках - PullRequest
2 голосов
/ 16 марта 2012

У меня есть 3 таблицы:

Molecule:
  id

Atom:
  id

MoleculeAtom: # Composite primary key
  molecule_id
  atom_id

Моя цель - убедиться, что никакая комбинация атомов, составляющих молекулу, не повторяется.Например, молекулу воды я бы сохранил в строке MoleculeAtom две строки;1 ряд для атома водорода и 1 ряд для атома кислорода.Как вы можете видеть, мне нужно убедиться, что ни одна другая молекула не имеет ТОЛЬКО водорода и кислорода, хотя могут быть и другие молекулы, которые включают водород и кислород.

На данный момент у меня есть вопрос, который определяет, какие молекулы включаютлибо водород, либо кислород, и только с 2 атомами в таблице MoleculeAtom.

SELECT
  m.id, m.name, (SELECT count(*) from molecule_atom where molecule_id = m.id group by molecule_id) as atomCount
FROM
  molecule AS m
INNER JOIN
  molecule_atom AS ma ON ma.molecule_id = m.id
WHERE
  ma.atom_id IN (1,2)
HAVING atomCount = 2;

Что возвращает (демонстративный фрагмент):

+----+----------------------------+-----------+
| id | name                       | atomCount |
+----+----------------------------+-----------+
| 53 | Carbon Dioxide             |         2 |
| 56 | Carbon Monoxide            |         2 |
+----+----------------------------+-----------+

(я знаю, что и CO, и CO2 имеютте же самые точные атомы, в разных количествах, но не обращайте внимания на то, что, поскольку я отслеживаю величины как другой столбец в той же таблице.)

На данный момент я извлекаю приведенные выше результаты и проверяю их atom_idsчерез PHP, что означает, что я должен выдать отдельный запрос для каждой молекулы, что кажется неэффективным, поэтому я искал, можно ли сделать эту проверку с использованием строго SQL.

Извините за любые ошибки, которые могут быть химическимисвязано, это было давно с chem101.

Ответы [ 4 ]

1 голос
/ 16 марта 2012

То, что вы запрашиваете, - это ограничение на уровне таблицы, которое недоступно в MySQL.В стандарте SQL-92 есть ASSERTION, что на самом деле является еще более общим (ограничение для более чем 1 таблицы).См. Ответы в этом вопросе: Почему СУБД не поддерживает ASSERTION для получения подробной информации и информации о некоторых продуктах (MS-Access), которые имеют такую ​​функциональность с ограничениями.

В MySQL выможет попытаться с помощью триггера имитировать такое ограничение.


Обновление:

Документация Firebird говорит, что разрешает подзапросы в ограничениях CHECK.

0 голосов
/ 10 апреля 2012

Как упоминал ypercube, MySQL не поддерживает утверждения, поэтому я закончил писать запрос, чтобы найти все молекулы, имеющие хотя бы один из атомов, принадлежащих новой молекуле, которую я пытаюсь создать, и имеющую такое же количество атомов,После запроса совпадений приложение проходит через каждую молекулу и определяет, имеют ли они те же атомы, что и новая молекула.Запрос выглядит следующим образом (предполагается, что я пытаюсь создать новую молекулу с 2 атомами):

SELECT 
    m.id,
    m.name,
    (SELECT GROUP_CONCAT(ma.atom_id) FROM molecule_atom AS ma WHERE ma.molecule_id = m.id GROUP BY ma.molecule_id HAVING (SELECT COUNT(ma.atom_id)) = 2) AS atoms
FROM
    molecule AS m
INNER JOIN
    molecule_atom AS mas ON mas.molecule_id = m.id
WHERE 
    mas.atom_id IN (1,2)

Затем в коде (PHP) я делаю:

foreach ($molecules as $molecule) {

    if (isset($molecule['atoms'])) {

        $diff = array_diff($newAtomIds, explode(',', $molecule['atoms']));

        // If there is no diff, then we have a match
        if (count($diff) === 0) {
            return $molecule['name'];
        }
    }
}

Спасибо за ответ каждого.

0 голосов
/ 16 марта 2012

Идея в том, чтобы найти пары молекул, чьи списки атомов не совпадают:

select m1.molecule_id as m1id, m2.molecule_id as m2id
from molecule_atom as m1, molecule_atom as m2,
    (select atom_id from molecule_atom as m where m.molecule_id=m1id) as m1a,
    (select atom_id from molecule_atom as m where m.molecule_id=m2id) as m2a,
where m1id < m2id and (((m1a - m2a) is not null) or ((m2a - m1a) is not null))
0 голосов
/ 16 марта 2012

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

...