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)
.