web-dev-qa-db-fra.com

Empêcher la «syntaxe d'entrée non valide pour le type json» dans Postgres

J'ai une colonne de texte qui contient JSON et planifie également du texte. Je veux le convertir en JSON, puis sélectionner une propriété particulière. Par exemple:

user_data
_________
{"user": {"name": "jim"}}
{"user": {"name": "sally"}}
some random data string

J'ai essayé:

select user_data::json#>'{user,name}' from users

Je reçois:

ERROR:  invalid input syntax for type json
DETAIL:  Token "some" is invalid.
CONTEXT:  JSON user_data, line 1: some...

Est-il possible d'empêcher cela?

11
Allyl Isocyanate

Si vous souhaitez ignorer les lignes avec un JSON non valide, vous devez d'abord test si le texte est du JSON valide. Vous pouvez le faire en créant une fonction qui tentera d'analyser la valeur et d'intercepter l'exception pour les valeurs JSON non valides.

CREATE OR REPLACE FUNCTION is_json(input_text varchar) RETURNS boolean AS $$
  DECLARE
    maybe_json json;
  BEGIN
    BEGIN
      maybe_json := input_text;
    EXCEPTION WHEN others THEN
      RETURN FALSE;
    END;

    RETURN TRUE;
  END;
$$ LANGUAGE plpgsql IMMUTABLE;

Lorsque vous avez cela, vous pouvez utiliser le is_json fonction dans une clause CASE ou WHERE pour affiner les valeurs valides.

-- this can eliminate invalid values
SELECT user_data::json #> '{user,name}'
FROM users WHERE is_json(user_data);

-- or this if you want to fill will NULLs
SELECT
  CASE
    WHEN is_json(user_data)
      THEN user_data::json #> '{user,name}'
    ELSE
      NULL
  END
FROM users;
5
Andy Carlson

Utilisez cette fonction:

create or replace function is_json(text)
returns boolean language plpgsql immutable as $$
begin
    perform $1::json;
    return true;
exception
    when invalid_text_representation then 
        return false;
end $$;

Tester:

with users(user_data) as (
values
    ('{"user": {"name": "jim"}}'),
    ('not json'),
    ('{"user": {"name": "sally"}}'),
    ('also not json')
)

select user_data::json#>'{user,name}' as name
from users
where is_json(user_data);

  name   
---------
 "jim"
 "sally"
(2 rows)
7
klin