如何解决查询具有不同数据类型的 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 举报,一经查实,本站将立刻删除。