如何在Postgresql中验证JSON是否有效?

Jak*_*zok 6 postgresql json

我有一个大型数据库,其中包含用JSON编写的分析数据.

我想过滤掉数据不正确的行:

  • 无效的json(有些行有类似的东西: '{"hello": "world'
  • 一些属性不是数组所以它会采取'{"products": [1,2,3]}'并将遗漏'{"products": 1}'

我想做那样的事情:

select * 
from analytics 
where (is_correct_json(json::json)) 
and (is_array(json::json->>'products'))
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

a_h*_*ame 17

这是另一个很好的例子,为什么从一开始就选择适当的数据类型有助于以后;)

没有内置函数来检查给定文本是否是有效的JSON.但是你可以写自己的:

create or replace function is_valid_json(p_json text)
  returns boolean
as
$$
begin
  return (p_json::json is not null);
exception 
  when others then
     return false;  
end;
$$
language plpgsql
immutable;
Run Code Online (Sandbox Code Playgroud)

注意:由于异常处理,这不会很快.如果你在许多无效值上调用它,这将大大减慢你的选择速度.

但是两者'{"products": 1}''{"products": [1,2,3]}'是有效的JSON文档.前者无效的事实是基于您的应用程序逻辑,而不是基于JSON语法.

要验证您是否需要类似的功能,请在调用时捕获错误 json_array_length()

create or replace function is_valid_json_array(p_json text, p_element text)
  returns boolean
as
$$
begin
  return json_array_length( p_json::json -> p_element) >= 0;
exception 
  when others then
     return false;  
end;
$$
language plpgsql
immutable;
Run Code Online (Sandbox Code Playgroud)


Erw*_*ter 12

Postgres 16 或更高版本

IS JSONPostgres 16(发布日期为 2023 年末)最终为此目的实现了 SQL/JSON 标准谓词。手册:

该谓词测试是否expression可以解析为 JSON(可能是指定类型)。如果指定了SCALARorARRAYOBJECT,则测试 JSON 是否属于该特定类型。如果WITH UNIQUE KEYS指定,则 expression还将测试 中的任何对象以查看它是否具有重复的键。

要验证该字符串是有效的 JSON 文字:

... WHERE string_column IS JSON
Run Code Online (Sandbox Code Playgroud)

要验证该字符串是有效的 JSON 数组文字:

... WHERE string_column IS JSON ARRAY
Run Code Online (Sandbox Code Playgroud)

(但请注意,这'{"products": [1,2,3]}'不是一个 JSON 数组,而是一个 JSON 对象。)

Postgres 15 或以上

这是a_horse_with_no_name 函数的改进版本,仍然使用昂贵的子事务来捕获invalid_text_representation错误。但它应该更快、更安全:

... WHERE string_column IS JSON
Run Code Online (Sandbox Code Playgroud)

主要差异

  • 标记该函数STRICT以获得更快的null输入结果。

  • 第一项也使其在功能上有所不同,返回null输入null- 这实际上就是修饰符的STRICT作用,RETURNS NULL ON NULL INPUT是相同的替代语法。这看起来更合理,因为null对于类型jsonjsonb(或 Postgres 中的任何数据类型)有效,我们可以根据需要测试true/ false/ null

  • PARALLEL SAFE遗憾的是,我们无法在 Postgres 9.6 或更高版本中标记该函数。该EXCEPTION部分使 Postgres 在输入函数时启动子事务,这与并行执行不兼容。有关的:

  • 此函数仅捕获“无效的文本表示”,而不捕获任何其他错误 - 即使其他错误似乎几乎不可能。

“f_is_json”只是我的命名约定,在自定义函数前加上“f_”前缀,以清楚地区分内置函数。

快速测试:

... WHERE string_column IS JSON ARRAY
Run Code Online (Sandbox Code Playgroud)

小提琴