在Postgres中防止'json类型的'无效输入语法'

All*_*ate 11 postgresql json plpgsql

我有一个包含JSON和计划文本的文本列.我想将其转换为JSON,然后选择一个特定的属性.例如:

user_data
_________
{"user": {"name": "jim"}}
{"user": {"name": "sally"}}
some random data string
Run Code Online (Sandbox Code Playgroud)

我试过了:

select user_data::json#>'{user,name}' from users
Run Code Online (Sandbox Code Playgroud)

我明白了:

ERROR:  invalid input syntax for type json
DETAIL:  Token "some" is invalid.
CONTEXT:  JSON user_data, line 1: some...
Run Code Online (Sandbox Code Playgroud)

有可能阻止这种情况吗?

kli*_*lin 7

使用此功能:

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 $$;
Run Code Online (Sandbox Code Playgroud)

测试:

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)
Run Code Online (Sandbox Code Playgroud)


And*_*son 5

如果要跳过使用无效JSON的行,则必须首先测试文本是否为有效JSON。您可以通过创建一个函数来尝试解析该值,并捕获无效JSON值的异常来实现此目的。

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;
Run Code Online (Sandbox Code Playgroud)

有了该名称后,可以is_jsonCASEor WHERE子句中使用该函数来缩小有效值的范围。

-- 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;
Run Code Online (Sandbox Code Playgroud)