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