json - T-SQL - 在过滤的 JSON 数组中搜索
问题描述
2017 年的 SQL 服务器。
表有存储 JSON 的OrderData
列。DataProperties
存储在那里的 JSON 示例:
{
"Input": {
"OrderId": "abc",
"Data": [
{
"Key": "Files",
"Value": [
"test.txt",
"whatever.jpg"
]
},
{
"Key": "Other",
"Value": [
"a"
]
}
]
}
}
因此,它是一个带有 Input 对象的对象,它具有 KVP 的 Data 数组 - 充满了带有 Key 字符串和 Value 字符串数组的对象。
还有我的问题 - 我需要根据示例 JSON 中的文件中的值查询行 - 简单的 LIKE 匹配%text%
。
此查询有效:
SELECT TOP 10 *
FROM OrderData CROSS APPLY OPENJSON(DataProperties,'$.Input.Data') dat
WHERE JSON_VALUE(dat.value, '$.Key') = 'Files' and dat.[key] = 0
AND JSON_QUERY(dat.value, '$.Value') LIKE '%2%'
问题是这个查询很慢,这不足为奇。
如何让它更快?
- 我无法使用 JSON_VALUE 创建计算列,因为我需要在数组中进行过滤。
- 我无法在“$.Input.Data”或“$.Input.Data[0].Values”上使用 JSON_QUERY 创建计算列 - 因为我需要在这个数组中使用
Key == "Files"
.
我已经搜索过,但您似乎无法创建也过滤数据的计算列,就像这次尝试一样:
ALTER TABLE OrderData
ADD aaaTest AS (select JSON_QUERY(dat.value, '$.Value')
OPENJSON(DataProperties,'$.Input.Data') dat
WHERE JSON_VALUE(dat.value, '$.Key') = 'Files' and dat.[key] = 0 );
错误:Subqueries are not allowed in this context. Only scalar expressions are allowed.
我有哪些选择?
- 添加带有索引的 Files 列并使用在插入/更新时填充此列的 INSERT/UPDATE 触发器?
- 创建一个“计算”该列的视图?无法添加索引,还是会很慢
到目前为止,只有选项 1. 有一些优点,但我不喜欢触发器,也许还有另一种选择?
解决方案
你可以试试这个:
注意:我添加了一个2
来text2
填充您的过滤器。我将两者都命名为复数"Values"
:
DECLARE @mockupTable TABLE(ID INT IDENTITY, DataProperties NVARCHAR(MAX));
INSERT INTO @mockupTable VALUES
(N'{
"Input": {
"OrderId": "abc",
"Data": [
{
"Key": "Files",
"Values": [
"test2.txt",
"whatever.jpg"
]
},
{
"Key": "Other",
"Values": [
"a"
]
}
]
}
}');
查询
SELECT TOP 10 *
FROM @mockupTable t
CROSS APPLY OPENJSON(t.DataProperties,'$.Input.Data')
WITH([Key] NVARCHAR(100)
,[Values] NVARCHAR(MAX) AS JSON) dat
WHERE dat.[Key] = 'Files'
AND dat.[Values] LIKE '%2%';
主要区别在于 -WITH
子句,它用于以类型化的方式并并排地返回对象内部的属性(类似于所有列的裸体- 但要好得多)。这避免了在您的...中使用昂贵的 JSON 方法OPENJSON
PIVOT
WHERE
提示:当我们返回Value
with 时,NVARCHAR(MAX) AS JSON
我们可以继续嵌套数组,并可能继续进行如下操作:
SELECT TOP 10 *
FROM @mockupTable t
CROSS APPLY OPENJSON(t.DataProperties,'$.Input.Data')
WITH([Key] NVARCHAR(100)
,[Values] NVARCHAR(MAX) AS JSON) dat
WHERE dat.[Key] = 'Files'
--we read the array again with `OPENJSON`:
AND 'test2.txt' IN(SELECT [Value] FROM OPENJSON(dat.[Values]));
您可以再使用一个CROSS APPLY
来添加数组的值并WHERE
直接对其进行过滤。
SELECT TOP 10 *
FROM @mockupTable t
CROSS APPLY OPENJSON(t.DataProperties,'$.Input.Data')
WITH([Key] NVARCHAR(100)
,[Values] NVARCHAR(MAX) AS JSON) dat
CROSS APPLY OPENJSON(dat.[Values]) vals
WHERE dat.[Key] = 'Files'
AND vals.[Value]='test2.txt'
只是检查一下...
推荐阅读
- c# - 从 SQL Server 表中获取超过百万行
- python - 如何为 pandas 数据框中的新列或 python 上的值计数设置参数?
- python - 操作错误没有这样的列 SQLite 3
- python - 你可以在不使用 linux 终端的情况下执行 python 文件吗?
- java - 如何在 GCP 上从 Java 代码执行 shell 命令
- python - 访问数据库时出现错误
- react-native - 如何处理反应导航自定义标题返回按钮
- python - 从具有匹配条件的集合中移除项目
- node.js - 通过 Codepipeline 在 Docker 上部署 Beanstalk 未完成
- php - 找不到方法商店和帖子 [LARAVEL]