繁体   English   中英

将 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"
            }
          ]
        }
      ]
    }
  ]
}

I want to save this JSON (conditon and rules fields in json file can be nested to multiple levels) in to SQL Server Tables and later wanted to construct the same JSON from these created tables. 我怎样才能做到这一点? 从这些表中,我计划获得其他 json 格式,这也是为什么决定将 json 拆分为表列的原因。

我认为需要创建一个递归 sql function 来做同样的事情。

我创建了下表来保存相同的 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)

这些表就够了吗? 能保存所有细节吗?

手动附加我添加到这些表中的值。

在此处输入图像描述

如何将此 JSON 保存到这些表中,以后将通过存储过程或查询从这些表中构造相同的 JSON?

请提供建议和样品!

实际上,您可以将列类型声明为 NVARCHAR(MAX),并将 json 字符串保存到其中。

我觉得我需要更多地了解您计划如何使用数据来回答这个问题。 我的心在告诉我,将这些信息存储在 MSSQL 中是有问题的,如果没有错,那就是有问题。

如果我必须这样做,我会将这些条件转换为分支内可旋转事件的矩阵查找表,因此对于每个可能的逻辑分支,您可以在查找中创建一行来评估它。

根据您所需的 output / 功能集,您可以执行上述操作,也可以按照 rkortekaas 的建议将所有内容放入 NVARCHAR 中。

由于 JSON 区分大小写,请检查您的架构定义和示例数据。 我发现表格的定义、它们的内容和您的 JSON 之间存在差异

在 MS SQL Server 2016 上测试的所有脚本

我在这个脚本中使用了一个临时表变量,但你可以不用它。 请参阅 SQL 小提琴中的示例

-- 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

SQL 小提琴

层次结构表-> 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

SQL 小提琴

您的用例似乎确实与 NoSql 选项(例如MongoDbAzure 表存储CosmosDB不知道你的价格)完美匹配。

摘自MongoDB页面:

在 MongoDB 中,数据作为文档存储。 这些文档以 JSON(JavaScript Object 表示法)格式存储在 MongoDB 中。 JSON 文档支持嵌入字段,因此相关数据和数据列表可以与文档一起存储,而不是外部表。

但是,从这里开始,我将假设您因其他原因与 SQL 服务器相关联。

您已声明您将只是将文档放入并取出相同的文档,因此 go 将所有字段分开是没有意义的。

SQL 服务器在处理文本字段方面比 IMO 更好。

我以前工作过的系统有以下几列(我会写 sql,但我不在我的开发机器上):

  • Id [主键,Integer,递增索引]
  • UserId [与此相关的外键 - 在您的情况下可能不是“用户”!]
  • Value [nvarchar(1000) 包含 json 作为字符串]

查找很容易根据外键完成。

但是,假设您希望它更像 NoSql,您可以:

  • Id [主键,Integer,递增索引]
  • Key [nvarchar(100) 您创建的字符串键,并且可以轻松地重新创建以查找值(例如User_43_Level_6_GameData - 此列应该有一个索引]
  • Value [nvarchar(1000) 包含 json 作为字符串]

我一直拥有 integer ID 的原因是为了避免碎片化 您显然可以使Value列更大。

Json 可以在 json object 和 Z466DEEC76ECDF5FCA6D38571F6324D54 字符串之间轻松转换。 在 Javascript 中,您将使用 Json ParseStringify 如果您使用的是 C#,您可以使用以下代码片段,尽管有很多方法可以完成此任务(对象可以嵌套任意深度)

.NET Object 至 Json

天气 w = new Weather("rainy", "windy", "32"); var jsonString = JsonSerializer.Serialize(w);

Json 到 .NET Object (C#)

var w = JsonSerializer.Deserialize(jsonString);

更新

虽然这是我过去做事的方式,但看起来 sql 服务器中有新选项来处理 JSON - OPENJSONJSONQUERY可能是潜在的选项,尽管我自己没有使用它们 - 他们仍然使用nvarchar JSON 列。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM