Search code examples
jsonpostgresqlfunctionruntime-errorparameter-passing

postgreSQL - ERROR: cannot extract elements from an object


I am a newbie to PostgreSQL. I have the below function and it is giving me an error. basically, I am passing JSON as a parameter to the function, extracting values, and inserting it into 2 tables. it is one to many relationships. so based on that one invoice has multiple line items:

PostgreSQL function:

    -- FUNCTION: public.insertorupdateinvoice(jsonb)

    -- DROP FUNCTION IF EXISTS public.insertorupdateinvoice(jsonb);

    CREATE OR REPLACE FUNCTION public.insertorupdateinvoice(
        invoice jsonb)
        RETURNS void
        LANGUAGE 'plpgsql'
        COST 100
        VOLATILE PARALLEL UNSAFE
    AS $BODY$
    Declare _invoiceid bigint;
    begin
      insert into invoicemaster (expenseid, invoiceno, transactiondate, totalinvoiceamount, invoicedoc, createdby, createdon)
      select (j.invoice->>'expenseid')::bigint, 
             j.invoice->>'invoiceno'::character, 
             (j.invoice->>'transactiondate')::date, 
             (j.invoice->>'totalinvoiceamount')::double precision, 
             j.invoice->>'invoicedoc'::character, 
             (j.invoice->>'createdby')::bigint,
             NOW()
      from jsonb_array_elements(invoice) as j(invoice)
      returning invoiceid into _invoiceid;

      insert into lineitemmaster (invoiceid, transactiondate, merchantname, amount, departmentid, policyid, itemdescription, 
                                  itemcategory, itemtype, status, isrejected, createdby, createdon)
      select _invoiceid::bigint, 
            (x.invoice->>'transactiondate')::date, 
            x.invoice->>'merchantname', 
            (x.invoice->>'amount')::double precision, 
            (x.invoice->>'departmentid')::integer, 
            (x.invoice->>'policyid')::integer, 
            x.invoice->>'itemdescription', 
            (x.invoice->>'itemcategory')::integer, 
            (x.invoice->>'itemtype')::integer, 
            (x.invoice->>'status')::boolean, 
            (x.invoice->>'isrejected')::boolean, 
            (x.invoice->>'createdby')::bigint,
            NOW()
      from jsonb_array_elements(invoice ->'lineitems') as x;
    end;
    $BODY$;

    ALTER FUNCTION public.insertorupdateinvoice(jsonb)
        OWNER TO postgres;

calling function as :

select * from insertorupdateinvoice('{"expenseid":1,
    "invoiceno":"04012022",
    "transactiondate":"2022-01-04",
    "totalinvoiceamount":1000.00,
    "invoicedoc":"invoicedoc",
    "createdby":1,
    "lineitems":[
      {"transactiondate":"2022-01-01", "merchantname":"Apple", "amount":"100.50", "departmentid":"1","policyid":"1", "itemdescription":"iphone 14 pro max", "itemcategory":"55", "itemtype":"499", "status":"true", "isrejected":"false", "createdby":"1"},
      {"transactiondate":"2022-01-02", "merchantname":"Samsung", "amount":"1050.35", "departmentid":"2","policyid":"2", "itemdescription":"samsung galaxy tab", "itemcategory":"40", "itemtype":"50", "status":"true", "isrejected":"false", "createdby":"1"},
      {"transactiondate":"2022-01-03", "merchantname":"Big bazar", "amount":"555.75", "departmentid":"3","policyid":"3", "itemdescription":"grocerry", "itemcategory":"5", "itemtype":"90", "status":"false", "isrejected":"false", "createdby":"1"}
    ]}');

getting error as below:

ERROR:  cannot extract elements from an object
CONTEXT:  SQL statement "insert into invoicemaster (expenseid, invoiceno, transactiondate, totalinvoiceamount, invoicedoc, createdby, createdon)
      select (j.invoice->>'expenseid')::bigint, 
             j.invoice->>'invoiceno'::character, 
             (j.invoice->>'transactiondate')::date, 
             (j.invoice->>'totalinvoiceamount')::double precision, 
             j.invoice->>'invoicedoc'::character, 
             (j.invoice->>'createdby')::bigint,
             NOW()
      from jsonb_array_elements(invoice) as j(invoice)
      returning invoiceid"
PL/pgSQL function insertorupdateinvoice(jsonb) line 5 at SQL statement
SQL state: 22023

Thanks


Solution

  • try this :

    CREATE OR REPLACE FUNCTION public.insertorupdateinvoice(
        invoice jsonb)
        RETURNS void
        LANGUAGE 'plpgsql'
        COST 100
        VOLATILE PARALLEL UNSAFE
    AS $BODY$
    Declare _invoiceid bigint;
    begin
      insert into invoicemaster (expenseid, invoiceno, transactiondate, totalinvoiceamount, invoicedoc, createdby, createdon)
      values ( (invoice->>'expenseid') :: bigint, 
               invoice->>'invoiceno', 
               (invoice->>'transactiondate') :: date, 
               (invoice->>'totalinvoiceamount') :: double precision, 
               invoice->>'invoicedoc', 
               (invoice->>'createdby') :: bigint,
               NOW()
             )
      returning invoiceid into _invoiceid;
    
      insert into lineitemmaster (invoiceid, transactiondate, merchantname, amount, departmentid, policyid, itemdescription, 
                                  itemcategory, itemtype, status, isrejected, createdby, createdon)
      select _invoiceid::bigint, 
            (x->>'transactiondate')::date, 
            x->>'merchantname', 
            (x->>'amount')::double precision, 
            (x->>'departmentid')::integer, 
            (x->>'policyid')::integer, 
            x->>'itemdescription', 
            (x->>'itemcategory')::integer, 
            (x->>'itemtype')::integer, 
            (x->>'status')::boolean, 
            (x->>'isrejected')::boolean, 
            (x->>'createdby')::bigint,
            NOW()
      from jsonb_array_elements(invoice ->'lineitems') as x;
    end;
    $BODY$;
    

    see dbfiddle