plpgsql извлекает массив перед циклом на его элементах

#json #postgresql #loops #plpgsql #jsonb

#json #postgresql #циклы #plpgsql #jsonb

Вопрос:

Я пытаюсь создать функцию plpg, принимающую в качестве параметра :

 [{'id_product': 100000158, 'd_price': '7,75'}, {'id_product': 100000339, 'd_price': '9,76'}]
  

Или, может быть :

 {'products': [{'id_product': 100000158, 'd_price': '7,75'}, {'id_product': 100000339, 'd_price': '9,76'}]}
  

Пока не могу определить наилучший подход.

Я хочу преобразовать этот объект или строку jsonb в массив, чтобы я мог выполнять цикл по нему. Идея состоит в том, чтобы выполнять цикл en каждый {'id_product': xxxxxxxxx, 'd_price': 'xxxxx'} раз, поэтому я, если значения в таблице одинаковы.

Каков наиболее оптимальный способ сделать это? Я все еще играю с функциями jsonb.

Ответ №1:

Вы можете создать функцию, содержащую JSONB_POPULATE_RECORDSET() function

 CREATE OR REPLACE FUNCTION fn_extract_elements( i_jsonb JSONB )
RETURNS TABLE (o_product VARCHAR(500), o_price VARCHAR(500))
AS $BODY$
BEGIN
RETURN QUERY

WITH tab AS 
(
 SELECT *
   FROM JSONB_POPULATE_RECORDSET(NULL::record,i_jsonb )
      AS tab(id_product VARCHAR(500), d_price VARCHAR(500))
 )
SELECT *
  FROM tab;

END 
$BODY$
LANGUAGE plpgsql;
  

и вызывайте таким образом, чтобы

 SELECT *  
  FROM fn_extract_elements(
'[{"id_product": "100000158", "d_price": "7,75"}, 
  {"id_product": "100000339", "d_price": "9,76"}]'
);

o_product   o_price
100000158   7,75
100000339   9,76
  

Demo

Ответ №2:

Вот решение для тех, кто, возможно, захочет сделать что-то подобное :

Я изменил ввод на что-то вроде : {0: [100000158, 7.76], 1: [100000339, 9.76]}

И функция :

 CREATE OR REPLACE FUNCTION public.check_d_price(
    p_products jsonb)
    RETURNS jsonb
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
AS $BODY$
DECLARE
        _key varchar;
        _real_price NUMERIC;
        _bad_price jsonb;
BEGIN

    FOR _key IN (
        SELECT jsonb_object_keys(p_products)
    )
    LOOP
        SELECT ei.price INTO _real_price FROM product pr JOIN ecom_input ei ON (pr.ecom_id,pr.sku) = (ei.ecom_id,ei.sku_supplier) WHERE pr.id = (p_products->_key->>0)::INT;
        IF _real_price <> (p_products->_key->>1)::NUMERIC THEN
                _bad_price = COALESCE(_bad_price,'{}'::jsonb) || jsonb_build_object((p_products->_key->>0)::TEXT,
                                                                                    jsonb_build_object('d_price', p_products->_key->>1,'new_price', _real_price));
        END IF;
    END LOOP;

    RETURN _bad_price;

END;
$BODY$;