如何通过主键将嵌套的JSON索引连接到SQL中的多行

如何通过主键将嵌套的JSON索引连接到SQL中的多行,json,sql-server,join,Json,Sql Server,Join,我试图用JSON更新SQL中的几行 我想将表行上的主键与嵌套在JS对象数组中的索引相匹配 样本数据: let json = [{ "header": object_data, "items": [{ "id": { "i": 0, "name": "item_id" }, "meta": { "data": object_data, "text": "some_text" } }, { "id":

我试图用JSON更新SQL中的几行

我想将表行上的主键与嵌套在JS对象数组中的索引相匹配

样本数据:

let json = [{
  "header": object_data,
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": object_data,
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": object_data,
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": object_data,
      "text": "some_text"
  }}]
}]
样本表:

i  |  json                     | item_id
---+---------------------------+---------
0  | entire_object_at_index_0  | item_id
4  | entire_object_at_index_4  | item_id4
17 | entire_object_at_index_17 | item_id17
索引处的整个对象,这意味着将项目数据附加到标题以为每行创建一个新对象

"header" "some_data",
"items": [{
  "id": {
    "i": 0,
    "name": "item_id1"
  },
  "meta": {
    "data": "some_data",
    "text": "some_text"
  }
}]
SQL:

更新:

这是为了改进我的答案,我在原始答案中遗漏了JSON内容的标题部分。当然,@jeroenmoster的答案是一个很好的解决方案,所以这只是另一种可能的方法。注意,若JSON内容的头部分是标量值,那个么应该使用JSON_值

表和JSON:

-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": {"key": "some_data"},
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": "some_data",
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
声明:

UPDATE #Data
SET #Data.Json = j.Json
FROM #Data
CROSS APPLY (
   SELECT
      JSON_QUERY(@json, '$[0].header') AS header,
      JSON_QUERY(j.[value], '$') AS items
   FROM OPENJSON(@json, '$[0].items') j
   WHERE JSON_VALUE(j.[value], '$.id.i') = #Data.[i]
   FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) j ([Json])  
UPDATE #Data
SET [json] = j.[value]
FROM #Data
LEFT JOIN (
   SELECT 
      [value],
      JSON_VALUE([value], '$.id.i') AS [i]
   FROM OPENJSON(@json, '$[0].items')
) j ON (#Data.[i] = j.[i])
原始答复:

一种可能的方法是使用OPENJSON和适当的连接:

表和JSON:

-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": {"key": "some_data"},
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": "some_data",
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
声明:

UPDATE #Data
SET #Data.Json = j.Json
FROM #Data
CROSS APPLY (
   SELECT
      JSON_QUERY(@json, '$[0].header') AS header,
      JSON_QUERY(j.[value], '$') AS items
   FROM OPENJSON(@json, '$[0].items') j
   WHERE JSON_VALUE(j.[value], '$.id.i') = #Data.[i]
   FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) j ([Json])  
UPDATE #Data
SET [json] = j.[value]
FROM #Data
LEFT JOIN (
   SELECT 
      [value],
      JSON_VALUE([value], '$.id.i') AS [i]
   FROM OPENJSON(@json, '$[0].items')
) j ON (#Data.[i] = j.[i])
更新:

这是为了改进我的答案,我在原始答案中遗漏了JSON内容的标题部分。当然,@jeroenmoster的答案是一个很好的解决方案,所以这只是另一种可能的方法。注意,若JSON内容的头部分是标量值,那个么应该使用JSON_值

表和JSON:

-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": {"key": "some_data"},
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": "some_data",
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
声明:

UPDATE #Data
SET #Data.Json = j.Json
FROM #Data
CROSS APPLY (
   SELECT
      JSON_QUERY(@json, '$[0].header') AS header,
      JSON_QUERY(j.[value], '$') AS items
   FROM OPENJSON(@json, '$[0].items') j
   WHERE JSON_VALUE(j.[value], '$.id.i') = #Data.[i]
   FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) j ([Json])  
UPDATE #Data
SET [json] = j.[value]
FROM #Data
LEFT JOIN (
   SELECT 
      [value],
      JSON_VALUE([value], '$.id.i') AS [i]
   FROM OPENJSON(@json, '$[0].items')
) j ON (#Data.[i] = j.[i])
原始答复:

一种可能的方法是使用OPENJSON和适当的连接:

表和JSON:

-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": {"key": "some_data"},
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
-- Table
CREATE TABLE #Data (
   i int,
   [json] nvarchar(max),
   item_id nvarchar(100)
)
INSERT INTO #Data
   (i, [json], [item_id])
VALUES
   (0 , N'entire_object_at_index_0',  N'item_id'),
   (4 , N'entire_object_at_index_4',  N'item_id4'),
   (17, N'entire_object_at_index_17', N'item_id17')

-- JSON
DECLARE @json nvarchar(max) = N'[{
  "header": "some_data",
  "items": [{
    "id": {
      "i": 0,
      "name": "item_id"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 4,
      "name": "item_id4"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
    }
  }, {
    "id": {
      "i": 17,
      "name": "item_id17"
    },
    "meta": {
      "data": "some_data",
      "text": "some_text"
  }}]
}]'
声明:

UPDATE #Data
SET #Data.Json = j.Json
FROM #Data
CROSS APPLY (
   SELECT
      JSON_QUERY(@json, '$[0].header') AS header,
      JSON_QUERY(j.[value], '$') AS items
   FROM OPENJSON(@json, '$[0].items') j
   WHERE JSON_VALUE(j.[value], '$.id.i') = #Data.[i]
   FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) j ([Json])  
UPDATE #Data
SET [json] = j.[value]
FROM #Data
LEFT JOIN (
   SELECT 
      [value],
      JSON_VALUE([value], '$.id.i') AS [i]
   FROM OPENJSON(@json, '$[0].items')
) j ON (#Data.[i] = j.[i])

重复其他属性的要求使这有点复杂,因为我们需要显式地构建一个新对象。即便如此,这也不难:

更新someTable 设置 [json]= 选择 选择 header=json_query@json,“$.header”, items=json_queryN'['+items.item+N'] 对于json路径,不带数组包装器 , item\u id=items.item\u id 从…起openjson@json,“$.items”和 项nvarcharmax“$”为json, 项目_idvarchar50'$.id.name', i int“$.id.i” 项目 在[someTable]上联接someTable.i=items.i
在这里,我假设@json已经从它的数组中解包,就像您的查询所假设的那样。如果不是,请在外部查询中将$[0]替换为$。

重复其他属性的要求使这一点有点复杂,因为我们需要显式地构建一个新对象。即便如此,这也不难:

更新someTable 设置 [json]= 选择 选择 header=json_query@json,“$.header”, items=json_queryN'['+items.item+N'] 对于json路径,不带数组包装器 , item\u id=items.item\u id 从…起openjson@json,“$.items”和 项nvarcharmax“$”为json, 项目_idvarchar50'$.id.name', i int“$.id.i” 项目 在[someTable]上联接someTable.i=items.i
在这里,我假设@json已经从它的数组中解包,就像您的查询所假设的那样。如果不是,则在外部查询中将$[0]替换为$。

json中应该以什么结尾?元?元数据?持有id和meta的对象?还有别的吗?换句话说,之后桌子应该是什么样子?另外,数组中的索引是否真正相关,或者我们可以通过匹配i来解决所有问题?在JSON中,它是一个新对象,具有该键/索引的标题数据和项数据。索引不是真正相关的,它只是将表键i与对象索引id.i匹配。因此,需要明确的是,在表的每一行中,标题和项目数组都应该重复,项目数组在每种情况下只有一个元素?您是否可以假定结构,即标题和项目?我这样问是因为这比说即使有人添加了一个必须复制到新对象的新属性,查询也需要工作要简单。在前一种情况下,我们可以选择,在后一种情况下,我们必须在替换方面变得棘手,因为T-SQL没有方便的方法来编辑JSON数组。是的,头应该在每一行中重复,项应该只使用一个索引,但仍然像原始对象一样格式化,即头:数据,项:[data\u for_one\u index].json中应该包含什么内容?元?元数据?持有id和meta的对象?还有别的吗?换句话说,之后桌子应该是什么样子?另外,数组中的索引是否真正相关,或者我们可以通过匹配i来解决所有问题?在JSON中,它是一个新对象,具有该键/索引的标题数据和项数据。索引不是真正相关的,它只是将表键i与对象索引id.i匹配。因此,需要明确的是,在表的每一行中,标题和项目数组都应该重复,项目数组在每种情况下只有一个元素?您是否可以假定结构,即标题和项目?我这样问是因为这比说即使有人添加了一个必须复制到新对象的新属性,查询也需要工作要简单。在前一种情况下,我们可以选择,在后一种情况下,我们必须在替换方面变得棘手,因为T-SQL没有co
编辑JSON数组的简便方法。是的,标题应在每一行中重复,项目应仅采用一个索引,但格式仍应与原始对象相同,即标题:data,项目:[data_for_one_index]。@Matthew:标题实际上是一个字符串,如您的示例所示,还是一个任意对象?json_值在后一种情况下不起作用,应该使用json_查询,而如果header实际上是一个值,则json_查询将不起作用。header是测试数据上的任意对象select似乎工作正常,尽管我得到了一个多部分标识符无法绑定items.item上的错误,但是更新失败了…这可能还有另一个问题。。。谢谢你的帮助!!我在SSMS 18.1中也看到了同样的问题,但这似乎是Intellisense的一个虚假错误-实际的T-SQL是根据实际的表进行测试的。@Matthew:header实际上是一个字符串(如示例中所示)还是一个任意对象?json_值在后一种情况下不起作用,应该使用json_查询,而如果header实际上是一个值,则json_查询将不起作用。header是测试数据上的任意对象select似乎工作正常,尽管我得到了一个多部分标识符无法绑定items.item上的错误,但是更新失败了…这可能还有另一个问题。。。谢谢你的帮助!!我在SSMS18.1中看到了同样的问题,但这似乎是Intellisense的一个虚假错误——实际的T-SQL是根据实际的表进行测试的。