Postgres Запрашивает/фильтрует JSONB с вложенными массивами

0

Вопрос

Ниже приведено мое требование к образцу

Мне нужны клиенты, которые отвечают всем нижеперечисленным условиям

  1. В стране "xyz", зарегистрированной в период с 2019 по 2021 год.
  2. Должен быть хотя бы один счет с балансом от 10000 до 13000, а филиал - "abc" и даты транзакций между 20200110 и 20210625. Он отформатирован и хранится в виде номера
  3. Должен иметь по крайней мере один адрес в состоянии "state1" и PIN-коды между 625001 и 625015

Ниже приведена структура таблицы

        CREATE TABLE IF NOT EXISTS customer_search_ms.customer
        (
            customer_id integer,
            customer_details jsonb
        )
    

В таблице могут быть миллионы строк. Я создал индекс GIN типа jsonb_ops в столбце customer_details, так как мы также будем проверять условия существования и сравнение диапазонов

Ниже приведен пример данных в столбце JSONB customer_data

customer_id : 1

    {
        "customer_data": {
            "name": "abc",
            "incorporated_year": 2020,
            "country":"xyz",
            "account_details": [
                {
                    "transaction_dates": [
                        20180125, 20190125, 20200125,20200525
                    ],
                    "account_id": 1016084,
                    "account_balance": 2000,
                    "account_branch": "xyz"
                },
                {
                    "transaction_dates": [
                        20180125, 20190125, 20200125
                    ],
                    "account_id": 1016087,
                    "account_balance": 12010,
                    "account_branch": "abc"
                }
            ],
            "address": [
                {
                    "address_id": 24739,
                    "door_no": 4686467,
                    "street_name":"street1",
                    "city": "city1",
                    "state": "state1",
                    "pin_code": 625001
                },
                {
                    "address_id": 24730,
                    "door_no": 4686442,
                    "street_name":"street2",
                    "city": "city1",
                    "state": "state1",
                    "pin_code": 625014
                }
            ]
        }
    }

Теперь запрос, который я написал выше, таков

SELECT  c.customer_id,
        c.customer_details
FROM customer_search_ms.customer c
WHERE c.customer_details @@ CAST('$.customer_data.country ==  "xyz" && $.customer_data.incorporated_year >= 2019 && $.customer_data.incorporated_year <= 2021 ' AS JSONPATH)
AND c.customer_details @? CAST('$.customer_data.account_details[*] ? (@.account_balance >=  10000) ? (@.account_balance <=  13000) ?(@.account_branch ==  "abc") ? (@.transaction_dates >=  20200110) ? (@.transaction_dates <=  20210625)' AS JSONPATH)
AND c.customer_details @? CAST('$.customer_data.address[*] ? (@.state ==  "state1") ? (@.pin_code >=  625001) ? (@.pin_code <= 625015)  ' AS JSONPATH)

Чтобы справиться с описанным выше сценарием, это лучший способ написать. Можно ли объединить все 3 критерия (клиент/учетная запись/адрес) в одно выражение? В таблице будут миллионы строк. Я придерживаюсь мнения, что это одно выражение, и попадание в базу данных даст наилучшую производительность. Можно ли объединить эти 3 условия в одно выражение

1

Лучший ответ

0

Ваш запрос не выдает мне ошибку, о которой вы сообщаете. Скорее, он работает, но дает "неправильные" результаты по сравнению с тем, что вы хотите. В нем есть несколько ошибок, которые не являются синтаксическими ошибками, а просто дают неправильные результаты.

Ваш первый jsonpath выглядит нормально. Это логическое выражение, и @@ проверяет, дает ли это выражение true.

У вашего второго jsonpath есть две проблемы. Это дает список объектов, которые соответствуют вашим условиям. Но объекты не являются логическими, поэтому @@ будет недоволен и вернет SQL NULL, который здесь трактуется так же, как false. Вместо этого вам нужно проверить, пуст ли этот список. Вот что @? делает, так что используйте это вместо @@. Кроме того, ваши даты хранятся в виде 8-значных целых чисел, но вы сравниваете их с 8-символьными строками. В jsonpath такие сравнения между типами приводят к нулю JSON, что здесь трактуется так же, как и false. Поэтому вам нужно либо изменить хранилище на строки, либо изменить литералы, с которыми они сравниваются, на целые числа.

Ваш третий jsonpath также имеет @@ проблема. И это имеет обратную проблему с типом, у вас есть pin-код, сохраненный в виде строк, но вы проверяете их на целых числах. Наконец, у вас есть "pin-код", написанный с ошибкой в одном случае.

2021-11-24 20:58:29

Спасибо, Джейнс. Я исправил код и данные в исходном сообщении. Из-за конфиденциального характера я должен был опубликовать приготовленные данные и допустил ошибку в этом. Я не могу воспроизвести сценарий ошибки. Есть ли какой-либо лучший подход для запроса, приведенного выше, с 3 условиями в предложении where. Я думаю, что если я смогу сделать это как одно условие вместо 3, это будет лучше. Любое руководство будет мне очень полезно. Спасибо
Balaji Govindan

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................