简体   繁体   中英

Postgres Check for Empty JSONB Fields

I want to be able to ignore or prevent an INSERT from occurring if there is a JSON object with keys but no values from within a Postgres function.Here is a small, contrived example:

DROP TABLE IF EXISTS mytable;
create table mytable(
a text,
b text
);

CREATE OR REPLACE FUNCTION insert_to_table(
somedata JSONB
)
RETURNS VOID AS $$
BEGIN 
insert into mytable (a, b) select a,b from jsonb_populate_recordset(null::mytable, $1::jsonb);
END;
$$ LANGUAGE plpgsql;

select insert_to_table('[{"a":1,"b":2},{"a":3,"b":4}, {"a":null, "b": null}, {"a": null, "b": "some data"}]');

This will insert 4 records, with the first row being 1,2 and the next row being 3,4 . The third row is "", "" , and the forth is "", some data .

In this scenario, rows 1,2, and 4 are valid. I want to ignore 3 and prevent it from being inserted.

I do not want a blank row, and my data/table will be much larger than what is listed (roughly 20 fields in the table, and 20 key/value pairs in the JSON).

Most likely I will need to loop over the array and pick out JSON object where ALL the keys are null and not just 1 or 2.

How can I do that?

In Postgres you can refer to a complete row using the name of the table (alias) in the query and compare that to NULL. A record is considered NULL if all columns are null. So you can do:

create or replace function insert_to_table(somedata jsonb)
returns void as $$
begin 
    insert into mytable (a, b) 
    select a, b 
    from jsonb_populate_recordset(null::mytable, somedata) as t
    where not (t is null);
end;
$$ language plpgsql;

Note that where t is not null is something different then where not (t is null) . This works regardless of the number of columns or their data types.

To visualize the logic. The following:

select a,b,
       not (t is null) as "not (t is null)", 
       t is null as "t is null", 
       t is not null as "t is not null"
from jsonb_populate_recordset(null::mytable, 
       '[{"a":1,"b":2},
         {"a":3,"b":4}, 
         {"a":null, "b": null}, 
         {"a": null, "b": "some data"}]'::jsonb) as t(a,b)

returns:

a | b         | not (t is null) | t is null | t is not null
--+-----------+-----------------+-----------+--------------
1 | 2         | true            | false     | true         
3 | 4         | true            | false     | true         
  |           | false           | true      | false        
  | some data | true            | false     | false        

Unrelated:

The cast $1::jsonb is useless as you have declared the parameter of that type already.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM