Вы здесь все усложняете. Вам не нужно запускать несколько запросов в al oop, просто используйте один запрос :
SELECT d1.name as drug_1, d2.name as drug_2, description
FROM interactions i
INNER JOIN drugs d1 ON i.id1 = d1.id
INNER JOIN drugs d2 ON i.id2 = d2.id
WHERE
d1.id in (... id list, see below ...)
AND d2.id = (... same id list, see below ...)
AND d1.id < d2.id
Я использовал здесь синтаксис INNER JOIN
, а не несколько таблиц в FROM
, чтобы сгруппировать условия соединения в выделенное место, поэтому условия WHERE
легче рассуждать.
Вышеуказанные все идентификаторы drug_list["drug_list_ids"]
передаются обоим in (....)
условиям, но затем ограничить базу данных только допустимыми комбинациями с предложением d1.id < d2.id
. Это генерирует полный набор возможных (упорядоченных) комбинаций между d1.id
и d2.id
, как у вас для l oop, хотя и со строгим отсортированным порядком (с использованием (8, 1548)
и (8, 3579)
вместо (1548, 8)
и (3579, 8)
).
Psycopg2 фактически принимает кортежи в качестве значений заполнителей и расширяет их до правильного синтаксиса для ... IN ...
тестирования; в этом случае драйвер включает скобки:
query_string = """\
SELECT d1.name as drug_1, d2.name as drug_2, description
FROM interactions i
INNER JOIN drugs d1 ON i.id1 = d1.id
INNER JOIN drugs d2 ON i.id2 = d2.id
WHERE
d1.id in %s
AND d2.id in %s
AND d1.id < d2.id
"""
with pg_get_cursor(pool) as cursor:
cursor.execute(query_string, (
tuple(drug_list["drug_list_ids"]),
tuple(drug_list["drug_list_ids"])
))
ddi_list = cursor.fetchall()
или вы можете использовать Postgres ... = ANY(ARRAY[...])
test вместо ... IN ...
и использовать тот факт, что psycopg2 интерполирует списки в виде ARRAY
значений :
query_string = """\
SELECT d1.name as drug_1, d2.name as drug_2, description
FROM interactions i
INNER JOIN drugs d1 ON i.id1 = d1.id
INNER JOIN drugs d2 ON i.id2 = d2.id
WHERE
d1.id = ANY(%s)
AND d2.id = ANY(%s)
AND d1.id < d2.id
"""
with pg_get_cursor(pool) as cursor:
cursor.execute(query_string, (drug_list["drug_list_ids"], drug_list["drug_list_ids"]))
ddi_list = cursor.fetchall()
Если это было невозможно, немного сложнее превратить ваши циклы в понимание списка. Не потому, что списочные выражения не могут обрабатывать вложенные циклы (просто перечислять их во вложенном порядке слева направо), а потому, что вам нужно использовать множественные операторы в теле l oop для получения результирующих значений. Тем не менее, поскольку * psychog2 cursor.execute()
всегда возвращает None
, вы можете использовать cursor.execute(...) or cursor
для создания следующего итератора до l oop, так что у вас будет что-то вроде:
[v ... for ... in outer loops ... for v in (cursor.execute(...) or cursor)]
Это использует тот факт, что вы можете l oop прямо над курсором, чтобы получить строки. В любом случае, нет необходимости вызывать cursor.fetchall()
и не нужно проверять, были ли результаты для этого указанного c запроса.
Ваши вложенные циклы for
можно выразить гораздо более компактно с помощью itertools.combinations()
:
from itertools import combinations
query_string = """\
SELECT d1.name as drug_1, d2.name as drug_2, description
FROM interactions i
INNER JOIN drugs d1 ON i.id1 = d1.id
INNER JOIN drugs d2 ON i.id2 = d2.id
WHERE d1.id = %s AND d2.id = %s
"""
with pg_get_cursor(pool) as cursor:
combos = combinations(drug_list["drug_list_ids"], r=2)
ddi_list = [v for id1, id2 in combos for v in (cursor.execute(query_string, (id1, id2)) or cursor)]
Однако, это совсем не эффективно (отправка множества отдельных запросов в базу данных), и при этом оно не настолько читабельно. И не обязательно, как показано выше.
Если вы должны иметь более жесткий контроль по-прежнему над своими парами идентификаторов, вам придется использовать вложенный тест кортежа; поместите столбцы d1.id
и d2.id
в массив и используйте тест IN ((v1, v2), (v3, v4), ...)
с правой стороной, переданный в cursor.execute()
как кортеж кортежей:
from itertools import combinations
query_string = """\
SELECT d1.name as drug_1, d2.name as drug_2, description
FROM interactions i
INNER JOIN drugs d1 ON i.id1 = d1.id
INNER JOIN drugs d2 ON i.id2 = d2.id
WHERE
(d1.id, d2.id) IN %s
"""
# list of [id1, id2] lists
combos = tuple(combinations(drug_list["drug_list_ids"], r=2))
with pg_get_cursor(pool) as cursor:
cursor.execute(query_string, (combos,))
ddi_list = cursor.fetchall()