当记录包含 json 或字符串的混合时,如何在 Postgres 中防止 'invalid input syntax for type json'
How to prevent 'invalid input syntax for type json' in Postgres, when records contain a mix of json or strings
我有一个包含 JSON 和计划文本的文本列。我想将其转换为 JSON,然后 select 一个特定的 属性。例如:
user_data
_________
{"user": {"name": "jim"}}
{"user": {"name": "sally"}}
some random data string
我试过:
select user_data::json#>'{user,name}' from users
我得到:
ERROR: invalid input syntax for type json
DETAIL: Token "some" is invalid.
CONTEXT: JSON user_data, line 1: some...
是否可以避免这种情况?
如果要跳过无效 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;
有了它,您可以在 CASE
或 WHERE
子句中使用 is_json
函数来缩小有效值的范围。
-- 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;
使用这个函数:
create or replace function is_json(text)
returns boolean language plpgsql immutable as $$
begin
perform ::json;
return true;
exception
when invalid_text_representation then
return false;
end $$;
测试:
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)
其他人已经提出了检查 JSON 是否有效的方法,但我觉得与其检查它,不如先投它?
我使用这个函数(JSONB,但你可以很容易地把它改成JSON):
CREATE OR REPLACE FUNCTION safe_cast_to_jsonb(input TEXT) RETURNS JSONB AS
$$
DECLARE
output JSONB DEFAULT NULL;
BEGIN
BEGIN
output := input::JSONB;
EXCEPTION
WHEN OTHERS THEN RAISE NOTICE 'INVALID JSONB';
RETURN NULL;
END;
RETURN output;
END;
$$ LANGUAGE plpgsql;
我有一个包含 JSON 和计划文本的文本列。我想将其转换为 JSON,然后 select 一个特定的 属性。例如:
user_data
_________
{"user": {"name": "jim"}}
{"user": {"name": "sally"}}
some random data string
我试过:
select user_data::json#>'{user,name}' from users
我得到:
ERROR: invalid input syntax for type json
DETAIL: Token "some" is invalid.
CONTEXT: JSON user_data, line 1: some...
是否可以避免这种情况?
如果要跳过无效 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;
有了它,您可以在 CASE
或 WHERE
子句中使用 is_json
函数来缩小有效值的范围。
-- 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;
使用这个函数:
create or replace function is_json(text)
returns boolean language plpgsql immutable as $$
begin
perform ::json;
return true;
exception
when invalid_text_representation then
return false;
end $$;
测试:
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)
其他人已经提出了检查 JSON 是否有效的方法,但我觉得与其检查它,不如先投它? 我使用这个函数(JSONB,但你可以很容易地把它改成JSON):
CREATE OR REPLACE FUNCTION safe_cast_to_jsonb(input TEXT) RETURNS JSONB AS
$$
DECLARE
output JSONB DEFAULT NULL;
BEGIN
BEGIN
output := input::JSONB;
EXCEPTION
WHEN OTHERS THEN RAISE NOTICE 'INVALID JSONB';
RETURN NULL;
END;
RETURN output;
END;
$$ LANGUAGE plpgsql;