PostgreSQL - сравнение списка python со строками таблицы

некоторое время безуспешно пытался найти это в интернете.

У меня есть список на языке python, который выглядит следующим образом:

[{'id': 5, 'field1': True}, {'id': 6, 'field1': False}]

Это просто список словарей, содержащих пары ключ/значение.

Теперь я спрашиваю себя, есть ли способ найти SQL таблицу по каждому id в списке и вернуть строку только если 'field1' отличается.

Допустим, моя таблица выглядит следующим образом:

id   field1
-----------
5    True
6    True

Учитывая, что ряд с id поля 6 отличается значением поля1, только этот ряд должен быть включен в результирующий запрос.

Есть ли способ достичь этого с помощью SQL или мне придется перебирать их вручную? Мой вариант использования включает много строк, и этот процесс будет повторяться много раз, поэтому я пытаюсь найти наиболее эффективный способ сделать это.

В качестве примечания: я использую Postgres.

Спасибо!

В PostgreSQL есть несколько способов сделать это, используя предложение WHERE IN:

SELECT *
FROM test
WHERE id IN (5, 6) AND (id, field1) NOT IN ((5, True), (6, False))

или JOIN в таблицу значений:

SELECT test.*
FROM test
JOIN (VALUES (5, True), (6, False)) AS v(id, field1)
ON test.id = v.id AND test.field1 != v.field1

В обоих случаях для данных вашей выборки результат будет

id  field1
6   t

При больших объемах данных я бы ожидал, что запрос JOIN будет наиболее эффективным. Вы можете построить часть запроса VALUES, используя что-то вроде:

ll = [{'id': 5, 'field1': True}, {'id': 6, 'field1': False}]
','.join(str(tuple(d.values())) for d in ll)

что для данных вашей выборки дает:

(5, True),(6, False)

Ваши данные выглядят как массив JSON, который вы можете передать как есть:

SELECT t.*
FROM   jsonb_array_elements('[{"id": 5, "field1": true}, {"id": 6, "field1": false}]'::jsonb) j(obj)
JOIN   tbl t ON t.id     =  (obj->>'id')::int
            AND t.field1 <> (obj->>'field1')::bool

Так же, как подготовленный оператор (в Python для этого есть своя функция):

PREPARE qr1(json) AS 
SELECT t.*
FROM   json_array_elements($1) j(obj)
JOIN   tbl t ON t.id     =  (obj->>'id')::int
            AND t.field1 <> (obj->>'field1')::bool;

Тогда:

EXECUTE qr1('[{"id": 5, "field1": true}, {"id": 6, "field1": false}]');

db<>fiddle here

Обязательно иметь индекс на tbl (id, field1).

Вернуться на верх