Как найти точный шаблон в столбце с помощью оператора SQL LIKE? - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть таблица, как показано ниже

    date    |                                                   tags                                                   
------------+----------------------------------------------------------------------------------------------------------
 2018-10-24 | {"table": "bank_trans", "metric": "withdrawal", "location": "UK"}
 2018-10-24 | {"table": "bank_trans", "metric": "balance", "account_id": "477", "location": "ny", "country": "USA"}
 2018-10-24 | {"table": "bank_trans", "metric": "deposit", "location": "blr", "country": "IND"}
 2018-11-02 | {"table": "bank_trans", "metric": "balance", "account_id": "477"}

Если я хочу конкретную строку, которая содержит шаблон поиска, как показано ниже

select date, tags
from webhook_forecastmodel
where tags LIKE '%"table": "bank_trans"%' AND
      tags LIKE '%"metric": "balance"%' AND
      tags LIKE '%"account_id": "477"%';

В этом случае я получаю два результата

    date    |                                                   tags                                                   
------------+----------------------------------------------------------------------------------------------------------

 2018-10-24 | {"table": "bank_trans", "metric": "balance", "account_id": "477", "location": "ny", "country": "USA"}

 2018-11-02 | {"table": "bank_trans", "metric": "balance", "account_id": "477"}

Я понимаю, что запрос SQL возвращает мне строки, в которых соответствует шаблон.

Но мне нужна только строка, точно указанная в шаблоне поиска LIKE, которая "table": "bank_trans", "metric": "balance" и "account_id": "477", которая оставляет нам только одну строку

 2018-11-02 | {"table": "bank_trans", "metric": "balance", "account_id": "477"}

Есть ли какой-нибудь возможный способ, которым это могло бы быть достигнуто?

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

ОБНОВЛЕНИЕ : этот вопрос предполагает актуальную версию Postgres. Он не будет работать на устаревшей и более не поддерживаемой версии 9.2, но я все равно оставлю ее здесь для справки.


Как уже упоминалось в комментариях, не используйте LIKE, используйте JSON функции . Чтобы иметь возможность сделать это, вы должны привести значение:

select date, tags
from webhook_forecastmodel
where tags::jsonb @> '{"table": "bank_trans"}'::jsonb 
  AND tags::jsonb @> '{"metric": "balance"}'::jsonb 
  AND tags::jsonb @> '{"account_id": "477"'}::jsonb;

Оператор @> проверяет, содержит ли значение с левой стороны пару ключ / значение с правой стороны.


Выше также будет возвращать строки, которые содержат больше, чем эти пары ключ / значение. Если вы хотите, чтобы те, которые содержат точно эти пары ключ / значение, используйте =

select date, tags
from webhook_forecastmodel
where tags::jsonb = '{"table": "bank_trans", 
                      "metric": "balance", 
                      "account_id": "477"}'::jsonb;

Тип данных jsonb нормализует пары ключ / значение, поэтому порядок ключей не имеет значения, и сравнение = будет работать правильно.

Онлайн пример: https://rextester.com/LYXHUC20162

В онлайн-примере у меня есть другой порядок ключей в столбце tags по сравнению с теми, которые используются для оператора =, чтобы продемонстрировать, что JSONB нормализует представление JSON.


Учитывая характер ваших данных, вероятно, лучше определить столбец как jsonb, чтобы избежать всех приведений.

0 голосов
/ 03 ноября 2018

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

Что еще более важно, вы, кажется, хотите, чтобы эта информация была в столбцах , поэтому вы должны поместить ее туда.

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

select date, tags
from webhook_forecastmodel
where tags LIKE '%"table": "bank_trans"%' AND
      tags LIKE '%"metric": "balance"%' AND
      tags LIKE '%"account_id": "477"%' AND
      tags NOT LIKE '%,%,%,%';  -- not more than three key/value pairs
...