将 JSON 文件保存到 SQL 服务器数据库表
Saving JSON file to SQL Server Database tables
我有一个嵌套的 JSON 文件,如下所示(条件和规则可以嵌套到多个级别)
{
"condition": "and",
"rules": [
{
"field": "26",
"operator": "=",
"value": "TEST1"
},
{
"field": "36",
"operator": "=",
"value": "TEST2"
},
{
"condition": "or",
"rules": [
{
"field": "2",
"operator": "=",
"value": 100
},
{
"field": "3",
"operator": "=",
"value": 12
},
{
"condition": "or",
"rules": [
{
"field": "12",
"operator": "=",
"value": "CA"
},
{
"field": "12",
"operator": "=",
"value": "AL"
}
]
}
]
}
]
}
我想将此 JSON(json 文件中的条件和规则字段可以嵌套到多个级别)保存到 SQL 服务器表中,稍后想构建相同的JSON 来自这些创建的 table。我怎样才能做到这一点 ?从这些 table 我计划获得其他 json 格式,这也是为什么决定将 json 拆分为 table 列的原因。
我认为需要创建一个递归 sql 函数来做同样的事情。
我创建了以下 table 以保存相同的 json。
CREATE TABLE [Ruleset]
([RulesetID] [BIGINT] IDENTITY(1, 1) NOT NULL PRIMARY KEY,
[Condition] [VARCHAR](50) NOT NULL,
[ParentRuleSetID] [BIGINT] NULL
);
GO
CREATE TABLE [Rules]
([RuleID] [BIGINT] IDENTITY(1, 1) NOT NULL PRIMARY KEY,
[Fields] [VARCHAR](MAX) NOT NULL,
[Operator] [VARCHAR](MAX) NOT NULL,
[Value] [VARCHAR](MAX) NOT NULL,
[RulesetID] [BIGINT] NULL
FOREIGN KEY REFERENCES [Ruleset](RulesetID)
);
插入脚本如下,
INSERT INTO [Ruleset] values
('AND',0),
('OR',1),
('OR',2)
INSERT INTO [Rules] values
('26','=','TEST1',1),
('364','=','TEST2',1),
('2','=','100',2),
('3','=','12',2),
('12','=','CA',3),
('12','=','AL',3)
这些 table 够了吗?将能够保存所有详细信息吗?
手动附加我添加到这些 table 的值。
如何将这个 JSON 保存到这些 table 中,然后通过存储过程或查询从这些 table 构造相同的 JSON?
请提供建议和样品!
我觉得我需要更多地了解您打算如何使用这些数据来回答这个问题。我的心告诉我,将这些信息存储在 MSSQL 中是有问题的,如果没有错误,那就是有问题的。
如果我必须这样做,我会将这些条件转换为矩阵查找 table 您分支内的 rotatable 事件,因此对于每个可能的逻辑分支,您可以在查找以对此进行评估。
根据您所需的输出/功能集,您可以执行上述操作,也可以按照 rkortekaas 的建议将所有内容都放入 NVARCHAR 中。
您的用例看起来确实非常适合 NoSql 选项,例如 MongoDb, Azure Table storage, or CosmosDB(如果您不了解 CosmosDB,它可能会很贵)。
摘自 MongoDB 页:
In MongoDB, data is stored as documents. These documents are stored in
MongoDB in JSON (JavaScript Object Notation) format. JSON documents
support embedded fields, so related data and lists of data can be
stored with the document instead of an external table.
但是,从现在开始,我假设您由于其他原因绑定到 SQL 服务器。
您已经声明您将只是将文档放入并取出相同的文档,因此拆分所有字段的努力没有意义。
SQL 服务器在处理文本字段方面比以前的 IMO 要好得多。
我之前工作过的系统有以下列(我会写 sql,但我不在我的开发机器上):
Id
[主键,整数,递增索引]
UserId
[与此相关的外键 - 在您的情况下可能 不是 'user'!]
Value
[nvarchar(1000) 包含 json 作为字符串]
根据外键轻松查找。
但是,假设您希望它更像 NoSql,您可以:
Id
[主键,整数,递增索引]
Key
[nvarchar(100) 您制作的字符串键,可以轻松重新制作以查找值(例如 User_43_Level_6_GameData
- 此列应该有一个索引]
Value
[nvarchar(1000) 包含 json 作为字符串]
我一直使用整数 ID 的原因是为了避免 fragmentation。您显然可以使 Value
列更大。
Json 可以很容易地在 json 对象和 json 字符串之间转换。在 Javascript 中,您将使用 Json Parse and Stringify. If you are using C# you could use the following snippets,尽管有很多方法可以完成此任务(对象可以嵌套任意深度)
.NET 对象到 Json
天气 w = new Weather("rainy", "windy", "32");
var jsonString = JsonSerializer.Serialize(w);
Json 到 .NET 对象 (C#)
var w = JsonSerializer.Deserialize(jsonString);
更新
尽管这是我过去做事的方式,看起来 sql 服务器中有新的选项来处理 JSON - OPENJSON and JSONQUERY could be potential options, though I haven't used them myself - they still use nvarchar JSON列。
因为 JSON 区分大小写,请检查您的架构定义和样本数据。我发现 table 的定义、它们的内容与您的 JSON
之间存在差异
所有脚本在 MS SQL Server 2016
上测试
我在此脚本中使用了一个临时 table 变量,但您可以不用它。请参阅 SQL Fiddle
中的示例
-- JSON -> hierarchy table
DECLARE @ExpectedJSON NVARCHAR(MAX) = '
{
"condition": "and",
"rules": [
{
"field": "26",
"operator": "=",
"value": "TEST1"
},
{
"field": "36",
"operator": "=",
"value": "TEST2"
},
{
"condition": "or",
"rules": [
{
"field": "2",
"operator": "=",
"value": 100
},
{
"field": "3",
"operator": "=",
"value": 12
},
{
"condition": "or",
"rules": [
{
"field": "12",
"operator": "=",
"value": "CA"
},
{
"field": "12",
"operator": "=",
"value": "AL"
}
]
}
]
}
]
}
'
DECLARE @TempRuleset AS TABLE
(RulesetID BIGINT NOT NULL PRIMARY KEY,
condition VARCHAR(50) NOT NULL,
ParentRuleSetID BIGINT NOT NULL,
RulesJSON NVARCHAR(MAX)
)
;WITH ParseRuleset AS (
SELECT 1 AS RulesetID,
p.condition,
p.rules,
0 AS ParentRuleSetID
FROM OPENJSON(@ExpectedJSON, '$') WITH (
condition VARCHAR(50),
rules NVARCHAR(MAX) AS JSON
) AS p
UNION ALL
SELECT RulesetID + 1,
p.condition,
p.rules,
c.RulesetID AS ParentRuleSetID
FROM ParseRuleset AS c
CROSS APPLY OPENJSON(c.rules) WITH (
condition VARCHAR(50),
rules NVARCHAR(MAX) AS JSON
) AS p
where
p.Rules IS NOT NULL
)
INSERT INTO @TempRuleset (RulesetID, condition, ParentRuleSetID, RulesJSON)
SELECT RulesetID,
condition,
ParentRuleSetID,
rules
FROM ParseRuleset
-- INSEERT INTO Ruleset ...
SELECT RulesetID,
condition,
ParentRuleSetID,
RulesJSON
FROM @TempRuleset
-- INSERT INTO Rules ...
SELECT RulesetID,
field,
operator,
value
FROM @TempRuleset tmp
CROSS APPLY OPENJSON(tmp.RulesJSON) WITH (
field VARCHAR(MAX),
operator VARCHAR(MAX),
value VARCHAR(MAX)
) AS p
WHERE p.field IS NOT NULL
层次结构 tables -> JSON:
CREATE TABLE Ruleset
(RulesetID BIGINT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
condition VARCHAR(50) NOT NULL,
ParentRuleSetID BIGINT NULL
);
GO
CREATE TABLE Rules
(RuleID BIGINT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
field VARCHAR(MAX) NOT NULL,
operator VARCHAR(MAX) NOT NULL,
value VARCHAR(MAX) NOT NULL,
RulesetID BIGINT NULL FOREIGN KEY REFERENCES Ruleset(RulesetID)
);
INSERT INTO Ruleset values
('and',0),
('or',1),
('or',2)
INSERT INTO Rules values
('26','=','TEST1',1),
('36','=','TEST2',1),
('2','=','100',2),
('3','=','12',2),
('12','=','CA',3),
('12','=','AL',3)
-- hierarchy table -> JSON
;WITH GetLeafLevel AS
(
SELECT Ruleset.RulesetID,
Ruleset.condition,
Ruleset.ParentRuleSetID,
1 AS lvl,
( SELECT field,
operator,
value
FROM Rules
WHERE Rules.RulesetID = Ruleset.RulesetID
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
) AS JSON_Rules
FROM Ruleset
WHERE ParentRuleSetID = 0
UNION ALL
SELECT Ruleset.RulesetID,
Ruleset.condition,
Ruleset.ParentRuleSetID,
GetLeafLevel.lvl + 1,
( SELECT field,
operator,
value
FROM Rules
WHERE Rules.RulesetID = Ruleset.RulesetID
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
)
FROM Ruleset
INNER JOIN GetLeafLevel ON Ruleset.ParentRuleSetID = GetLeafLevel.RulesetID
),
-- SELECT * FROM GetLeafLevel -- debug
ConcatReverseOrder AS
(
SELECT GetLeafLevel.*,
CONCAT('{"condition":"',
GetLeafLevel.condition,
'","rules":[',
GetLeafLevel.JSON_Rules,
']}'
) AS js
FROM GetLeafLevel
WHERE GetLeafLevel.lvl = (SELECT MAX(lvl) FROM GetLeafLevel)
UNION ALL
SELECT GetLeafLevel.*,
CONCAT('{"condition":"',
GetLeafLevel.condition,
'","rules":[',
GetLeafLevel.JSON_Rules,
',',
ConcatReverseOrder.js,
']}'
) AS js
FROM GetLeafLevel
INNER JOIN ConcatReverseOrder ON GetLeafLevel.RuleSetID = ConcatReverseOrder.ParentRuleSetID
)
-- SELECT * FROM ConcatReverseOrder -- debug
SELECT js
FROM ConcatReverseOrder
WHERE ParentRuleSetID = 0
其实你可以声明列类型为NVARCHAR(MAX),然后将json字符串存入其中。
我有一个嵌套的 JSON 文件,如下所示(条件和规则可以嵌套到多个级别)
{
"condition": "and",
"rules": [
{
"field": "26",
"operator": "=",
"value": "TEST1"
},
{
"field": "36",
"operator": "=",
"value": "TEST2"
},
{
"condition": "or",
"rules": [
{
"field": "2",
"operator": "=",
"value": 100
},
{
"field": "3",
"operator": "=",
"value": 12
},
{
"condition": "or",
"rules": [
{
"field": "12",
"operator": "=",
"value": "CA"
},
{
"field": "12",
"operator": "=",
"value": "AL"
}
]
}
]
}
]
}
我想将此 JSON(json 文件中的条件和规则字段可以嵌套到多个级别)保存到 SQL 服务器表中,稍后想构建相同的JSON 来自这些创建的 table。我怎样才能做到这一点 ?从这些 table 我计划获得其他 json 格式,这也是为什么决定将 json 拆分为 table 列的原因。
我认为需要创建一个递归 sql 函数来做同样的事情。
我创建了以下 table 以保存相同的 json。
CREATE TABLE [Ruleset]
([RulesetID] [BIGINT] IDENTITY(1, 1) NOT NULL PRIMARY KEY,
[Condition] [VARCHAR](50) NOT NULL,
[ParentRuleSetID] [BIGINT] NULL
);
GO
CREATE TABLE [Rules]
([RuleID] [BIGINT] IDENTITY(1, 1) NOT NULL PRIMARY KEY,
[Fields] [VARCHAR](MAX) NOT NULL,
[Operator] [VARCHAR](MAX) NOT NULL,
[Value] [VARCHAR](MAX) NOT NULL,
[RulesetID] [BIGINT] NULL
FOREIGN KEY REFERENCES [Ruleset](RulesetID)
);
插入脚本如下,
INSERT INTO [Ruleset] values
('AND',0),
('OR',1),
('OR',2)
INSERT INTO [Rules] values
('26','=','TEST1',1),
('364','=','TEST2',1),
('2','=','100',2),
('3','=','12',2),
('12','=','CA',3),
('12','=','AL',3)
这些 table 够了吗?将能够保存所有详细信息吗?
手动附加我添加到这些 table 的值。
如何将这个 JSON 保存到这些 table 中,然后通过存储过程或查询从这些 table 构造相同的 JSON?
请提供建议和样品!
我觉得我需要更多地了解您打算如何使用这些数据来回答这个问题。我的心告诉我,将这些信息存储在 MSSQL 中是有问题的,如果没有错误,那就是有问题的。
如果我必须这样做,我会将这些条件转换为矩阵查找 table 您分支内的 rotatable 事件,因此对于每个可能的逻辑分支,您可以在查找以对此进行评估。
根据您所需的输出/功能集,您可以执行上述操作,也可以按照 rkortekaas 的建议将所有内容都放入 NVARCHAR 中。
您的用例看起来确实非常适合 NoSql 选项,例如 MongoDb, Azure Table storage, or CosmosDB(如果您不了解 CosmosDB,它可能会很贵)。
摘自 MongoDB 页:
In MongoDB, data is stored as documents. These documents are stored in MongoDB in JSON (JavaScript Object Notation) format. JSON documents support embedded fields, so related data and lists of data can be stored with the document instead of an external table.
但是,从现在开始,我假设您由于其他原因绑定到 SQL 服务器。
您已经声明您将只是将文档放入并取出相同的文档,因此拆分所有字段的努力没有意义。
SQL 服务器在处理文本字段方面比以前的 IMO 要好得多。
我之前工作过的系统有以下列(我会写 sql,但我不在我的开发机器上):
Id
[主键,整数,递增索引]UserId
[与此相关的外键 - 在您的情况下可能 不是 'user'!]Value
[nvarchar(1000) 包含 json 作为字符串]
根据外键轻松查找。
但是,假设您希望它更像 NoSql,您可以:
Id
[主键,整数,递增索引]Key
[nvarchar(100) 您制作的字符串键,可以轻松重新制作以查找值(例如User_43_Level_6_GameData
- 此列应该有一个索引]Value
[nvarchar(1000) 包含 json 作为字符串]
我一直使用整数 ID 的原因是为了避免 fragmentation。您显然可以使 Value
列更大。
Json 可以很容易地在 json 对象和 json 字符串之间转换。在 Javascript 中,您将使用 Json Parse and Stringify. If you are using C# you could use the following snippets,尽管有很多方法可以完成此任务(对象可以嵌套任意深度)
.NET 对象到 Json
天气 w = new Weather("rainy", "windy", "32"); var jsonString = JsonSerializer.Serialize(w);
Json 到 .NET 对象 (C#)
var w = JsonSerializer.Deserialize(jsonString);
更新
尽管这是我过去做事的方式,看起来 sql 服务器中有新的选项来处理 JSON - OPENJSON and JSONQUERY could be potential options, though I haven't used them myself - they still use nvarchar JSON列。
因为 JSON 区分大小写,请检查您的架构定义和样本数据。我发现 table 的定义、它们的内容与您的 JSON
之间存在差异所有脚本在 MS SQL Server 2016
上测试我在此脚本中使用了一个临时 table 变量,但您可以不用它。请参阅 SQL Fiddle
中的示例-- JSON -> hierarchy table
DECLARE @ExpectedJSON NVARCHAR(MAX) = '
{
"condition": "and",
"rules": [
{
"field": "26",
"operator": "=",
"value": "TEST1"
},
{
"field": "36",
"operator": "=",
"value": "TEST2"
},
{
"condition": "or",
"rules": [
{
"field": "2",
"operator": "=",
"value": 100
},
{
"field": "3",
"operator": "=",
"value": 12
},
{
"condition": "or",
"rules": [
{
"field": "12",
"operator": "=",
"value": "CA"
},
{
"field": "12",
"operator": "=",
"value": "AL"
}
]
}
]
}
]
}
'
DECLARE @TempRuleset AS TABLE
(RulesetID BIGINT NOT NULL PRIMARY KEY,
condition VARCHAR(50) NOT NULL,
ParentRuleSetID BIGINT NOT NULL,
RulesJSON NVARCHAR(MAX)
)
;WITH ParseRuleset AS (
SELECT 1 AS RulesetID,
p.condition,
p.rules,
0 AS ParentRuleSetID
FROM OPENJSON(@ExpectedJSON, '$') WITH (
condition VARCHAR(50),
rules NVARCHAR(MAX) AS JSON
) AS p
UNION ALL
SELECT RulesetID + 1,
p.condition,
p.rules,
c.RulesetID AS ParentRuleSetID
FROM ParseRuleset AS c
CROSS APPLY OPENJSON(c.rules) WITH (
condition VARCHAR(50),
rules NVARCHAR(MAX) AS JSON
) AS p
where
p.Rules IS NOT NULL
)
INSERT INTO @TempRuleset (RulesetID, condition, ParentRuleSetID, RulesJSON)
SELECT RulesetID,
condition,
ParentRuleSetID,
rules
FROM ParseRuleset
-- INSEERT INTO Ruleset ...
SELECT RulesetID,
condition,
ParentRuleSetID,
RulesJSON
FROM @TempRuleset
-- INSERT INTO Rules ...
SELECT RulesetID,
field,
operator,
value
FROM @TempRuleset tmp
CROSS APPLY OPENJSON(tmp.RulesJSON) WITH (
field VARCHAR(MAX),
operator VARCHAR(MAX),
value VARCHAR(MAX)
) AS p
WHERE p.field IS NOT NULL
层次结构 tables -> JSON:
CREATE TABLE Ruleset
(RulesetID BIGINT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
condition VARCHAR(50) NOT NULL,
ParentRuleSetID BIGINT NULL
);
GO
CREATE TABLE Rules
(RuleID BIGINT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
field VARCHAR(MAX) NOT NULL,
operator VARCHAR(MAX) NOT NULL,
value VARCHAR(MAX) NOT NULL,
RulesetID BIGINT NULL FOREIGN KEY REFERENCES Ruleset(RulesetID)
);
INSERT INTO Ruleset values
('and',0),
('or',1),
('or',2)
INSERT INTO Rules values
('26','=','TEST1',1),
('36','=','TEST2',1),
('2','=','100',2),
('3','=','12',2),
('12','=','CA',3),
('12','=','AL',3)
-- hierarchy table -> JSON
;WITH GetLeafLevel AS
(
SELECT Ruleset.RulesetID,
Ruleset.condition,
Ruleset.ParentRuleSetID,
1 AS lvl,
( SELECT field,
operator,
value
FROM Rules
WHERE Rules.RulesetID = Ruleset.RulesetID
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
) AS JSON_Rules
FROM Ruleset
WHERE ParentRuleSetID = 0
UNION ALL
SELECT Ruleset.RulesetID,
Ruleset.condition,
Ruleset.ParentRuleSetID,
GetLeafLevel.lvl + 1,
( SELECT field,
operator,
value
FROM Rules
WHERE Rules.RulesetID = Ruleset.RulesetID
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
)
FROM Ruleset
INNER JOIN GetLeafLevel ON Ruleset.ParentRuleSetID = GetLeafLevel.RulesetID
),
-- SELECT * FROM GetLeafLevel -- debug
ConcatReverseOrder AS
(
SELECT GetLeafLevel.*,
CONCAT('{"condition":"',
GetLeafLevel.condition,
'","rules":[',
GetLeafLevel.JSON_Rules,
']}'
) AS js
FROM GetLeafLevel
WHERE GetLeafLevel.lvl = (SELECT MAX(lvl) FROM GetLeafLevel)
UNION ALL
SELECT GetLeafLevel.*,
CONCAT('{"condition":"',
GetLeafLevel.condition,
'","rules":[',
GetLeafLevel.JSON_Rules,
',',
ConcatReverseOrder.js,
']}'
) AS js
FROM GetLeafLevel
INNER JOIN ConcatReverseOrder ON GetLeafLevel.RuleSetID = ConcatReverseOrder.ParentRuleSetID
)
-- SELECT * FROM ConcatReverseOrder -- debug
SELECT js
FROM ConcatReverseOrder
WHERE ParentRuleSetID = 0
其实你可以声明列类型为NVARCHAR(MAX),然后将json字符串存入其中。