微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

查询具有不同数据类型的 PostgreSQL JSONB 列

如何解决查询具有不同数据类型的 PostgreSQL JSONB 列

作为我的 Postgresql 数据库中架构的一部分,目前运行版本 11,但如果它解除阻塞,我愿意升级我有一个 jsonb 列 data,其中包含跨行的各种结构的嵌套对象,我没有控制权。例如:

第 1 行可能是:{'rootProperty': { 'nestedProperty': 'someStrVal' }}

和第 2 行可能具有类似的架构:{'rootProperty': { 'nestedProperty': 2,'othernestedProperty': 'someOtherString' }}

尝试根据 jsonb 列中的属性查询行/行子集时遇到了困难,这些属性在各行中具有不同的类型。在此示例中,nestedProperty 是第 1 行中的字符串和第 2 行中的 int。

当我尝试运行诸如

之类的查询

SELECT * FROM TABLE WHERE data -> 'rootProperty' ->> 'nestedProperty' = 'someStrVal'

一切正常,但如果我尝试

SELECT * FROM TABLE WHERE data -> 'rootProperty' ->> 'nestedProperty' > 1

SELECT * FROM TABLE WHERE (data -> 'rootProperty' ->> 'nestedProperty')::int > 1

查询错误,分别为“运算符不存在:文本>整数”和“整数的无效输入语法:“someStrVal”。

有没有一种方法可以让 jsonb 列具有可变模式,这些模式可能具有重叠的结构,尽管具有不同的数据类型,并且仍然对它们进行查询?我不介意指定我要查找的类型,只要它可以跳过或绕过不符合该类型标准的行。

解决方法

为同一个属性使用不同类型的值一开始似乎很奇怪,但很可能你无法改变这种“设计”。

Postgres 12 引入了对 SQL/JSON path 表达式的支持,它对数据类型转换很宽容,并且在您尝试将 someStrVal 与数字进行比较时不会出错。

查询:

select *
from the_table
where data @@ '$.rootProperty.nestedProperty > 1'

将返回 nestedProperty 是大于 1 的有效数字的所有行。无法转换为数字的值将被静默忽略。

也可以写成:

where jsonb_path_exists(the_column,'$.rootProperty.nestedProperty ? (@ > 1)')

该值可以通过使用带有第三个参数的 jsonb_path_exists() 作为参数传递:

where jsonb_path_exists(the_column,'$.rootProperty.nestedProperty ? (@ > $nr)','{"nr": 1}')

最后一个参数可以通过参数占位符传递,例如在 Java 中:

where jsonb_path_exists(the_column,cast(? as jsonb))

然后:

PreparedStatement pstmt = conn.prepareStatement(...);
pstmt.setString(1,"{\"nr\": 1}");
,

我不记得确切是在哪个版本中引入的,但您可以使用 struct ContentView: View { @State var userIsAuthenticated: Bool = false init(auth: State<Bool>) { navAppearance.configureWithOpaqueBackground() navAppearance.backgroundColor = UIColor(Color("MyBlue")) navAppearance.titleTextAttributes = [.foregroundColor: UIColor.white] navAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white] UINavigationBar.appearance().standardAppearance = navAppearance UINavigationBar.appearance().scrollEdgeAppearance = navAppearance self._userIsAuthenticated = auth } var body: some View { if userIsAuthenticated { TabView { NavigationView { RosterView(auth: $userIsAuthenticated) } .navigationViewStyle(StackNavigationViewStyle()) .tabItem { Label("My Roster",systemImage: "calendar") } NavigationView { PayView(auth: $userIsAuthenticated) } .tabItem { Label("My Pay",systemImage: "dollarsign.circle") } NavigationView { LeaveView(auth: $userIsAuthenticated) } .tabItem { Label("My Leave",systemImage: "airplane.circle") } NavigationView { MessagesView(auth: $userIsAuthenticated) } .tabItem { Label("Messages",systemImage: "bubble.left.and.bubble.right") } } .foregroundColor(.white) .accentColor(.white) .onAppear(perform: { UITabBar.appearance().isTranslucent = false UITabBar.appearance().barTintColor = UIColor(named: "MyBlue") UITabBar.appearance().unselectedItemTintColor = UIColor.lightText UITabBar.appearance().tintColor = UIColor.white }) } else { AuthView(auth: $userIsAuthenticated) } } } 函数和 json_typeof 表达式将属性的值转换为正确的类型。我会使用 SQL 函数来使我的查询保持整洁:

CASE

然后就是:

CREATE FUNCTION jsonb_to_integer(jsonb,text) RETURNS integer AS
$$
    SELECT CASE jsonb_typeof($1->$2) 
           WHEN 'number' THEN ($1->>$2)::integer 
           ELSE null 
           END 
$$
LANGUAGE SQL
STABLE
RETURNS NULL ON NULL INPUT;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。