Postgres Упрощение запросов JSONB - PullRequest
1 голос
/ 12 марта 2020

У меня есть некоторый рабочий код, который извлекает записи из таблицы форм, где 'mail@example.com' отображается как значение JSON в одном из полей JSONB, column_a, column_b, column_c или column_d.

SELECT * 
FROM forms f
WHERE exists (SELECT * 
              FROM jsonb_each_text(f.column_a) as e(ky,val)
              WHERE e.val = 'mail@example.com')   
UNION

SELECT * 
FROM forms f
WHERE exists (SELECT * 
              FROM jsonb_each_text(f.column_b) as e(ky,val)
              WHERE e.val = 'mail@example.com')
UNION

SELECT * 
FROM forms f
WHERE exists (SELECT * 
              FROM jsonb_each_text(f.column_c) as e(ky,val)
              WHERE e.val = 'mail@example.com')
UNION

SELECT * 
FROM forms f
WHERE exists (SELECT * 
              FROM jsonb_each_text(f.column_d) as e(ky,val)
              WHERE e.val = 'mail@example.com');

JSON в столбцах похож на:

{ "xyz":"mail@example.com", "def":"mail2@example.com", "lmn":"mail3@example.com" }

Несмотря на то, что код работает, он выглядит очень многократно повторяющимся. Учитывая, что я не могу изменить структуру JSON, есть ли более краткий способ построения этого запроса, и какие индексы я должен построить для этих столбцов для лучшей производительности?

1 Ответ

2 голосов
/ 12 марта 2020

Почему бы не использовать or?

SELECT f.* 
FROM forms f
WHERE EXISTS (SELECT * 
              FROM jsonb_each_text(f.column_a) as e(ky,val)
              WHERE e.val = 'mail@example.com'
             ) OR
      EXISTS (SELECT * 
              FROM jsonb_each_text(f.column_b) as e(ky,val)
              WHERE e.val = 'mail@example.com'
             ) OR
      . . .

Предположительно, это также устраняет необходимость удаления дубликатов, поэтому запрос также должен выполняться быстрее.

РЕДАКТИРОВАТЬ:

Если вам нужны источники, вы можете использовать коррелированные подзапросы:

SELECT f.* 
FROM (SELECT f.*,
             EXISTS (SELECT * 
                     FROM jsonb_each_text(f.column_a) as e(ky,val)
                     WHERE e.val = 'mail@example.com'
                    ) as in_column_a,
             EXISTS (SELECT * 
                     FROM jsonb_each_text(f.column_b) as e(ky,val)
                     WHERE e.val = 'mail@example.com'
                    ) as in_column_b,
             . . .
      FROM forms f
     ) 
WHERE in_column_a OR in_column_b OR . . .

Это не так эффективно, потому что оно не закорачивает оценку, когда находит совпадение. С другой стороны, в нем перечислены все столбцы, которые соответствуют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...