2015-01-08 4 views
2

У меня есть список значений python и таблица postgresql с определенным столбцом в нем. Я хотел бы знать, для каждого элемента в моем списке python есть ли какая-либо строка в таблице с этим идентификатором.Проверка наличия списка значений python в psycopg2/postgresql

Например, предположим, что у меня есть этот список Python:

vals = [4, 8, 15, 16, 23, 42] 

а также о том, что запрос:

select my_col from my_table; 

дает:

[4, 5, 6, 7, 8] 

Тогда я хотел бы запрос что возвращается:

[True, True, False, False, False, False] 

Я мог бы прокрутить список и выполнить новый «select exists» для каждого значения, но я задавался вопросом, есть ли способ сделать это за один вызов?

Я ограничен PostGreSQL 9.0

+0

Почему бы просто не использовать 2 строки Python после 'select'? Один, чтобы сделать этот результат в set 's', а затем просто' [x в s для x в vals] '? –

+0

Так что вытащите всю колонку DB в python? Это сработает. В какой-то момент у него будет несколько сотен миллионов записей, поэтому не уверен, что это будет плохо для производительности? (Столбец будет проиндексирован.) – JoeZuntz

+0

Пример просто для иллюстрации - я действительно не выбираю полный столбец в своем коде. – JoeZuntz

ответ

2

Этот вопрос скорее о SQL, чем о Python или psycopg. Я бы использовать запрос:

SELECT my_col = ANY(your_array_here) FROM my_table; 

, чтобы получить результат в «таблице порядка» или:

SELECT A.x = ANY(SELECT my_col FROM my_table) 
    FROM (SELECT * FROM unnest(your_array_here) x) A; 

, чтобы получить результат в «порядке Vals».

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

curs.execute("SELECT my_col = ANY(%s) from my_table", (vals,)) 

или:

curs.execute("""SELECT A.x = ANY(SELECT my_col FROM my_table) 
        FROM (SELECT * FROM unnest(%s) x) A""", (vals,)) 

Обратите внимание, что связанная переменная аргумент должен быть dict или кортеж, и вы хотите связать полный список с одной переменной в запросе, что означает, что вы должны использовать 1-элементный набор ((vals,)), а не пытаться передать vals напрямую.

+0

Это прекрасно - большое спасибо. И вы правы, это больше вопрос sql! – JoeZuntz

1

Я думаю, что это требует сочетания строки форматирования и заполнителей (потому что вам нужно один %s за единицу в vals):

vals = [4, 8, 15, 16, 23, 42] 

query = 'select distinct(my_col) from my_table where my_col in (' 
query += ', '.join(['%s'] * len(vals)) 
query += ')' 

cursor.execute(query, vals) 
theset = {t[0] for t in cursor.fetchall()} 

theboollist = [v in theset for v in vals] 

Этот подход должен гарантировать, что количество данных, которые вы отправляете в БД (для предложения where ... in), и сумма, которую вы получаете от него, равна O(N), где N равно len(vals); Я думаю, что было бы логически невозможно сделать лучше, чем в условиях большого О.

+1

Помогло бы использовать 'select distinct my_col', чтобы гарантировать' len (cursor.fetchall()) <= N'? – unutbu

+0

@unutbu уверен, если дублирование возможно в 'my_col' - не рассматривалось в этом случае, теперь редактирование для исправления, tx. –