Postgresql: выбрать строки по условию ИЛИ - включая прохождение массива json - PullRequest
1 голос
/ 26 мая 2020

У меня есть таблица, созданная по следующему запросу:

create table data
(
    id integer not null unique,
    owner text,
    users jsonb not null
);

Таблица выглядит так:

+----+-------+---------------------------------------------+
| id | owner |                    users                    |
+----+-------+---------------------------------------------+
|  1 | alice | []                                          |
|  2 | bob   | [{"accountId": "alice", "role": "manager"}] |
|  3 | john  | [{"accounId": "bob", "role": "guest"}]      |
+----+-------+---------------------------------------------+

Мне нужно получить строки 1 и 2 от имени Алисы.

Получение строк на основе владельцев работает идеально:

SELECT *
FROM data
WHERE owner = 'alice'

Получение строк на основе jsonb немного сложнее, хотя и управляемо:

SELECT *
FROM data, jsonb_array_elements(users) x
WHERE (x ->> 'accountId') = 'alice'

Но объединение их вместе меня просто основанные на jsonb:

SELECT *
FROM data, jsonb_array_elements(users) x
WHERE owner = 'alice' OR (x ->> 'accountId') = 'alice'

Как мне получить выделение, которое выглядит следующим образом?

+----+-------+---------------------------------------------+
| id | owner |                    users                    |
+----+-------+---------------------------------------------+
|  1 | alice | []                                          |
|  2 | bob   | [{"accountId": "alice", "role": "manager"}] |
+----+-------+---------------------------------------------+

Еще лучше, если я могу получить выделение, которое выглядит следующим образом

+----+----------+
| id |   role   |
+----+----------+
|  1 | owner    |
|  2 | manager  |
+----+----------+

1 Ответ

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

Проблема заключается в пустом массиве json, который вытесняет соответствующую строку из набора результатов, когда cross join редактируется с jsonb_array_elements(). Вместо этого вы можете создать left join lateral:

select d.*
from data d
left join lateral jsonb_array_elements(d.users) as x(js) on 1 = 1
where 'alice' in (d.owner, x.js ->> 'accountId')

Обратите внимание, что если ваш массив всегда содержит 0 или 1 элемент, вам не нужно боковое соединение - ваш запрос будет проще сформулировать как:

select d.*
from data d
where 'alice' in (d.owner, d.data -> 0 ->> 'accountId')

Демо на DB Fiddle - оба запроса возвращают:

id | owner | users                                      
-: | :---- | :------------------------------------------
 1 | alice | []                                         
 2 | bob   | [{"role": "manager", "accountId": "alice"}]
...