使用 TSQL OPENJSON 如何使用动态键名从 JSON 数组中提取值
Using TSQL OPENJSON how do I extract a value from JSON array with a dynamic key name
我有一个带有内部属性数组的 json 文档。在这些属性之一上,键名更改 dynamically/randomly。我可以轻松提取除最后一个讨厌的属性之外的所有数据点。我在过去使用 OPENJSON 发现或使用的所有方法都依赖于已知的密钥名称。
在"inner"数组里面,第一个属性会有一个键名变化。我想提取与该动态键关联的值,但不知道该键究竟是什么。希望下面的代码能比我用文字更好地描述问题。
以下是 JSON 文档的格式以提高可读性...
{
"outer1": {
"inner1": {
"dynamicKey123": "attribute1",
"staticKey1": "attribute2",
"staticKey2": "attribute3",
"staticKey3": "attribute4"
}
},
"outer2": {
"inner2": {
"dynamicKeyABC": "attribute1",
"staticKey1": "attribute2",
"staticKey2": "attribute3",
"staticKey3": "attribute4"
}
}
}
一些用于测试的代码...
CREATE TABLE openjson_test (json_col VARCHAR(MAX));
INSERT INTO openjson_test (json_col)
VALUES ('{"outer1":{"inner1":{"dynamicKey123":"attribute1","staticKey1":"attribute2","staticKey2":"attribute3","staticKey3":"attribute4"}},"outer2":{"inner2":{"dynamicKeyABC":"attribute1","staticKey1":"attribute2","staticKey2":"attribute3","staticKey3":"attribute4"}}}');
到目前为止我开发的查询中有问题的部分被注释掉了...
SELECT
json_col,
so.[key] AS soKey,
si.[key] AS siKey,
si.[value] AS siValue,
--ar.dynamicKey,
ar.staticKey1,
ar.staticKey2,
ar.staticKey3
FROM openjson_test
CROSS APPLY OPENJSON(json_col) so
CROSS APPLY OPENJSON(json_col, '$.' + so.[key]) si
CROSS APPLY OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key])
WITH (
--dynamicKey VARCHAR(256) '$.dynamicKey???', How do I extract this value without knowing the key
staticKey1 VARCHAR(256) '$.staticKey1',
staticKey2 VARCHAR(256) '$.staticKey2',
staticKey3 VARCHAR(256) '$.staticKey3'
) ar
您可以使用不带 WITH
子句的 OPENJSON
并过滤掉具有已知名称的列:
SELECT json_col,
so.[key] AS soKey,
si.[key] AS siKey,
si.[value] AS siValue,
ar2.Value AS dynamicKey,
ar.staticKey1,
ar.staticKey2,
ar.staticKey3
FROM dbo.openjson_test t
CROSS APPLY OPENJSON(t.json_col) so
CROSS APPLY OPENJSON(json_col, '$.' + so.[key]) si
CROSS APPLY OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key])
WITH (
staticKey1 VARCHAR(256) '$.staticKey1',
staticKey2 VARCHAR(256) '$.staticKey2',
staticKey3 VARCHAR(256) '$.staticKey3'
) ar
CROSS APPLY (
SELECT *
FROM OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key])
WHERE [Key] NOT IN ('staticKey1','staticKey2','staticKey3')
) ar2
我建议采用 条件聚合
的方法
SELECT
so.[key] AS soKey,
si.[key] AS siKey,
MAX(CASE WHEN attr.[key] NOT IN('staticKey1','staticKey2','staticKey3') THEN attr.[value] END) AS DynamicAttr,
MAX(CASE WHEN attr.[key]='staticKey1' THEN attr.[value] END) AS attrKey1,
MAX(CASE WHEN attr.[key]='staticKey2' THEN attr.[value] END) AS attrKey2,
MAX(CASE WHEN attr.[key]='staticKey3' THEN attr.[value] END) AS attrKey3
FROM openjson_test
CROSS APPLY OPENJSON(json_col) so
CROSS APPLY OPENJSON(json_col, '$.' + so.[key]) si
CROSS APPLY OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key]) attr
GROUP BY so.[key],si.[key];
此技术用于 PIVOT
场景,但允许更通用的逻辑。
我有一个带有内部属性数组的 json 文档。在这些属性之一上,键名更改 dynamically/randomly。我可以轻松提取除最后一个讨厌的属性之外的所有数据点。我在过去使用 OPENJSON 发现或使用的所有方法都依赖于已知的密钥名称。
在"inner"数组里面,第一个属性会有一个键名变化。我想提取与该动态键关联的值,但不知道该键究竟是什么。希望下面的代码能比我用文字更好地描述问题。
以下是 JSON 文档的格式以提高可读性...
{
"outer1": {
"inner1": {
"dynamicKey123": "attribute1",
"staticKey1": "attribute2",
"staticKey2": "attribute3",
"staticKey3": "attribute4"
}
},
"outer2": {
"inner2": {
"dynamicKeyABC": "attribute1",
"staticKey1": "attribute2",
"staticKey2": "attribute3",
"staticKey3": "attribute4"
}
}
}
一些用于测试的代码...
CREATE TABLE openjson_test (json_col VARCHAR(MAX));
INSERT INTO openjson_test (json_col)
VALUES ('{"outer1":{"inner1":{"dynamicKey123":"attribute1","staticKey1":"attribute2","staticKey2":"attribute3","staticKey3":"attribute4"}},"outer2":{"inner2":{"dynamicKeyABC":"attribute1","staticKey1":"attribute2","staticKey2":"attribute3","staticKey3":"attribute4"}}}');
到目前为止我开发的查询中有问题的部分被注释掉了...
SELECT
json_col,
so.[key] AS soKey,
si.[key] AS siKey,
si.[value] AS siValue,
--ar.dynamicKey,
ar.staticKey1,
ar.staticKey2,
ar.staticKey3
FROM openjson_test
CROSS APPLY OPENJSON(json_col) so
CROSS APPLY OPENJSON(json_col, '$.' + so.[key]) si
CROSS APPLY OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key])
WITH (
--dynamicKey VARCHAR(256) '$.dynamicKey???', How do I extract this value without knowing the key
staticKey1 VARCHAR(256) '$.staticKey1',
staticKey2 VARCHAR(256) '$.staticKey2',
staticKey3 VARCHAR(256) '$.staticKey3'
) ar
您可以使用不带 WITH
子句的 OPENJSON
并过滤掉具有已知名称的列:
SELECT json_col,
so.[key] AS soKey,
si.[key] AS siKey,
si.[value] AS siValue,
ar2.Value AS dynamicKey,
ar.staticKey1,
ar.staticKey2,
ar.staticKey3
FROM dbo.openjson_test t
CROSS APPLY OPENJSON(t.json_col) so
CROSS APPLY OPENJSON(json_col, '$.' + so.[key]) si
CROSS APPLY OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key])
WITH (
staticKey1 VARCHAR(256) '$.staticKey1',
staticKey2 VARCHAR(256) '$.staticKey2',
staticKey3 VARCHAR(256) '$.staticKey3'
) ar
CROSS APPLY (
SELECT *
FROM OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key])
WHERE [Key] NOT IN ('staticKey1','staticKey2','staticKey3')
) ar2
我建议采用 条件聚合
的方法SELECT
so.[key] AS soKey,
si.[key] AS siKey,
MAX(CASE WHEN attr.[key] NOT IN('staticKey1','staticKey2','staticKey3') THEN attr.[value] END) AS DynamicAttr,
MAX(CASE WHEN attr.[key]='staticKey1' THEN attr.[value] END) AS attrKey1,
MAX(CASE WHEN attr.[key]='staticKey2' THEN attr.[value] END) AS attrKey2,
MAX(CASE WHEN attr.[key]='staticKey3' THEN attr.[value] END) AS attrKey3
FROM openjson_test
CROSS APPLY OPENJSON(json_col) so
CROSS APPLY OPENJSON(json_col, '$.' + so.[key]) si
CROSS APPLY OPENJSON(json_col, '$.' + so.[key] + '.' + si.[key]) attr
GROUP BY so.[key],si.[key];
此技术用于 PIVOT
场景,但允许更通用的逻辑。