Уточнение данных, хранящихся в SQLite - как объединить несколько контактов? - PullRequest
5 голосов
/ 25 мая 2010

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

Проблемный фон

Представьте себе эту проблему. У вас есть молекула воды, которая находится в контакте с другими молекулами (если контакт представляет собой водородную связь, вокруг моей воды может быть еще 4 молекулы). Как и на следующем рисунке (A, B, C, D - некоторые другие атомы, а точки означают контакт).

 A   B
 |   |
 H   H
  . .
   O
  / \
 H   H
 .   .
 C   D

У меня есть информация обо всех точках, и мне нужно устранить воду в центре и создать записи, описывающие контакты A-C, A-D, A-B, B-C, B-D и C-D.

Структура базы данных

В настоящее время у меня есть следующая структура в базе данных:

Таблица atoms:

  • "id" integer PRIMARY KEY,
  • "amino" char(3) NOT NULL, (HOH для воды или другого значения)
  • другие столбцы, идентифицирующие атом

Таблица contacts:

  • "acceptor_id" integer NOT NULL, (атом рядом с моим водородом, здесь C или D)
  • "donor_id" integer NOT NULL, (здесь A или B)
  • "directness" char(1) NOT NULL, (это должно быть D для прямого и W для опосредованного водой)
  • другие столбцы о контакте, например расстояние

EDIT: Как бы выглядели данные в случае, изображенном ранее.

atoms

id|atom|amino
1 | O  | HOH
2 | N  | ARG  <- atom A from image
3 | S  | CYS  <- B 
4 | O  | SER  <- C
5 | N  | ARG  <- D

contacts:

donor_id|acceptor_id|directness
1        4           D
1        5           D
2        1           D
3        1           D

Из чего мне нужно сделать

contacts

donor_id|acceptor_id|directness
3        4           W            <- B-C
3        5           W            <- B-D
2        4           W            <- A-C
2        5           W            <- A-D
2        3           X            <- A-B    (These last two rows are escaping me,
4        5           X            <- C-D     there could be also row D-C, but not
                                             both C-D and D-C. A char 'X' could 
                                             be used to mark "no donor/acceptor")

Текущее решение (недостаточное)

Теперь я просматриваю все контакты, которые имеют donor.amino = "HOH". В этом примере, это будет выбор контактов из C и D. Для каждого из этих выбранных контактов я ищу контакты, имеющие тот же acceptor_id, что и donor_id в текущем выбранном контакте. Из этой информации я создаю новый контакт. В конце я удаляю все контакты в или из HOH.

Таким образом, я явно не могу создать контакты C-D и A-B (остальные 4 в порядке).

Если я попробую подобный подход - пытаясь найти два контакта с одинаковым donor_id, я получу дубликаты контактов (C-D и D-C).

Есть ли простой способ восстановить все шесть контактов без дубликатов?

Мне снится какой-то одностраничный SQL-запрос, который извлекает только эти шесть искомых строк. : -)
Тем не менее, любые другие идеи приветствуются.

Желательно сохранить информацию о том, кто является донором (где это возможно), но не является строго обязательным.

Большое спасибо всем, кто прочитал этот вопрос на данный момент.

Ответы [ 2 ]

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

Есть одно затруднение с вашим объяснением.

То, с чего вы начинаете, это ориентированный граф, где каждое ребро представляет соединение X => Y, где X - донор, а Y - акцептор. Таблица atoms является SQL-представлением этого графа.

То, что вы, кажется, хотите - это то, что не направлено . Таким образом, связь X-Y означает, что X и Y связаны через молекулу воды (или, конечно, некоторых других видов), но что X и Y могут быть как донорами, так и акцепторами. По этой причине ваша последняя таблица имеет неоднозначность (что вы заметили), поэтому некоторые ссылки могут возникать в любом случае. Мне кажется, это означает, что заголовки столбцов donor_id и acceptor_id в вашем последнем столбце не имеют никакого значения, которое вы объяснили. Это может быть мое замешательство, конечно.

Если все, что вам нужно, это таблица со всеми 6 ссылками в ней, каждая в одной строке, но не слишком беспокоиться о том, чтобы отследить, что происходит с донором / акцептором, тогда это работает для меня в sqlite3:

 create temporary view hoh_view as 
 select donor_id as id, atoms.id as hoh_id from contacts, atoms 
       where acceptor_id=atoms.id and atoms.amino='HOH' 
 union select acceptor_id as id, atoms.id as hoh_id from contacts, atoms 
       where donor_id=atoms.id and atoms.amino='HOH';

 select a.id, b.id from hoh_view as a, hoh_view as b 
       where a.id > b.id and a.hoh_id=b.hoh_id;

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

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

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

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

Ну, сложно привести примеры в комментариях, я решил опубликовать ответ:

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

sqlite> create table atoms (id INT, atom TEXT, amino TEXT);
sqlite> insert into atoms VALUES (1, 'O', 'HOH');
sqlite> insert into atoms VALUES (2, 'A', 'ARG');
sqlite> insert into atoms VALUES (3, 'B', 'CYS');
sqlite> insert into atoms VALUES (4, 'C', 'SER');
sqlite> insert into atoms VALUES (5, 'D', 'ARG');
sqlite> insert into atoms VALUES (6, 'O1', 'HOH');
sqlite> insert into atoms VALUES (7, 'A1', 'ARG');
sqlite> insert into atoms VALUES (8, 'B1', 'CYS');
sqlite> insert into atoms VALUES (9, 'C1', 'SER');
sqlite> insert into atoms VALUES (10, 'D1', 'ARG');
sqlite> select * from atoms;
1|O|HOH
2|A|ARG
3|B|CYS
4|C|SER
5|D|ARG
6|O1|HOH
7|A1|ARG
8|B1|CYS
9|C1|SER
10|D1|ARG

UPD

Вот исходные данные:

sqlite> .headers ON
sqlite> .mode columns
sqlite> select * from atoms;
id          atom        amino
----------  ----------  ----------
1           O           HOH
2           A           ARG
3           B           CYS
4           C           SER
5           D           ARG
6           O1          HOH
7           A1          ARG
8           B1          CYS
9           C1          SER
10          D1          ARG
sqlite> select * from contacts;
donor_id    acceptor_id  directness
----------  -----------  ----------
1           4            D
1           5            D
2           1            D
3           1            D
6           9            D
6           10           D
7           6            D
8           6            D

Вот запрос:

select
    c1.donor_id, c2.acceptor_id, 'W' as directness
from
    contacts c1, contacts c2, atoms a
where
    c1.acceptor_id = c2.donor_id
    and c1.acceptor_id=a.id
    and a.amino='HOH'
UNION ALL
select
    c1.donor_id, c2.donor_id, 'X' as directness
from
    contacts c1, contacts c2, atoms a
where
    c1.acceptor_id = c2.acceptor_id
    and c1.acceptor_id=a.id
    and a.amino='HOH'
    and c1.donor_id < c2.donor_id
UNION ALL
select
    c1.acceptor_id, c2.acceptor_id, 'X' as directness
from
    contacts c1, contacts c2, atoms a
where
    c1.donor_id = c2.donor_id
    and c1.donor_id=a.id
    and a.amino='HOH'
    and c1.acceptor_id < c2.acceptor_id;

Вот результат:

donor_id    acceptor_id  directness
----------  -----------  ----------
2           4            W
2           5            W
3           4            W
3           5            W
7           9            W
7           10           W
8           9            W
8           10           W
2           3            X
7           8            X
4           5            X
9           10           X
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...