存储具有可变值类型的扁平化 JSON(键值对)
Posted
技术标签:
【中文标题】存储具有可变值类型的扁平化 JSON(键值对)【英文标题】:Storing flattened JSON (key-value pairs) with variable value types 【发布时间】:2021-12-27 21:57:02 【问题描述】:我有没有定义架构的 JSON 文档。每个文档可能有不同的架构和值。
"location":
"latitude": 58.23,
"longitude": 25.11
,
"building": "A1",
"active": true,
"parameters": [ 1, "scanInterval": 1000 ]
这些 JSON 文档被扁平化 - 格式化为键值对。
"location.latitude": 58.23,
"location.longitude": 25.11,
"building": "A1",
"active": true,
"parameter[0]": 1,
"parameter[1].scanInterval": 1000
Key 总是 String。
Value可以是String、Number、Boolean。
这些键值对将存储在 SQL 表中。要求是能够根据 JSON 原生值过滤键值。
SELECT .... FROM ... WHERE [Key] = @key AND [Value] > @value; -- [Value] is integer/float
SELECT .... FROM ... WHERE [Key] = @key AND [Value] != @value; -- [Value] is bit/boolean
SELECT .... FROM ... WHERE [Key] = @key AND [Value] = @value; -- [Value] is string
这让我疑问 - 如何设计我的桌子?
选项 A) 投射。
CREATE TABLE [dbo].[OptionA](
....
[Key] [nvarchar](max),
[ValueType] [nvarchar](max)
[Value] [nvarchar](max)
)
始终将 [Value] 存储为 String,在查询数据时,选择匹配 [ValueType] 的行并转换值:
... WHERE [ValueType] = 'Number' AND [Key] = @key AND CAST([Value] AS FLOAT) > @value
选项 B) 每种值类型的列。
CREATE TABLE [dbo].[OptionB](
....
[Key] [nvarchar](50),
[StringValue] [nvarchar](50) NULL,
[NumericValue] [float] NULL,
[BooleanValue] [bit] NULL
)
有 3 列。每列有 1 个值类型。在所有 3 列中,只有 1 列可以包含值,其余为 NULL。
查询数据时,选择对应值类型的列:
SELECT .... FROM ... WHERE [Key] = @key AND [NumericValue] > @value
哪个选项产生最好的结果或总体上更好/看起来更好?或许还有其他更好的选择?
我更倾向于 A) 方法,但是所有的转换都可能会增加额外的复杂性,并且可能会影响性能。
【问题讨论】:
取决于您的用例,基本上基于意见。如果您经常查询这些内容,那么选项 B 似乎更好。如果您只是检索整个对象,也许使用选项 A。如果您有深度嵌套的对象,那么首先将它们保留为适当的 JSON 对象可能更容易(这可能是我会做的) 【参考方案1】:有点丑,not fully tested
,但也许这会给你一个正确的方向。
我应该注意SEQ
uence 是可选的
示例
Declare @JSON varchar(max) = '
"location":
"latitude": 58.23,
"longitude": 25.11
,
"building": "A1",
"active": true,
"parameters": [ 1, "scanInterval": 1000 ]
';
with cte0 as (
Select *
,spath = convert(varchar(max),[key])
,seq = convert(varchar(250),10000+row_number() over(order by 1/0))
From OpenJSON(@json,'$')
Union All
Select R.*
,spath = convert(varchar(max),concat(P.spath,case when try_convert(int,r.[key]) is not null and P.[type]>3 then quotename(r.[key]) else '.'+r.[key] end))
,seq = convert(varchar(250),concat(P.seq,'\',10000+row_number() over(order by 1/0)))
From cte0 P
Cross Apply OpenJSON(P.[Value],'$') R
Where P.[Type]>3
)
Select [key] = spath
,value
,[Type] = choose([Type],'string','numeric','bool','array','object')
from cte0
Where [type]<=3
Order By seq
结果
key value Type
location.latitude 58.23 numeric
location.longitude 25.11 numeric
building A1 string
active true bool
parameters[0] 1 numeric
parameters[1].scanInterval 1000 numeric
【讨论】:
以上是关于存储具有可变值类型的扁平化 JSON(键值对)的主要内容,如果未能解决你的问题,请参考以下文章