使用 SQL 服务器 JSON_VALUE 搜索 json 数组

tun*_*h24 6 sql sql-server

假设一个给定的 json 对象:

{"info":{"address":[{"town":"Belgrade"},{"town":"Paris"},{"town":"Madrid"}]}}
Run Code Online (Sandbox Code Playgroud)

SQL 服务器具有 JSON_VALUE 函数,可以在 WHERE 子句中使用它来匹配特定的 json 元素,例如

WHERE JSON_VALUE(columnName, $.info.address[1].town) = 'Belgrade'
Run Code Online (Sandbox Code Playgroud)

问题是它需要一个索引。如何在路径指定的所有数组元素中搜索?

Zho*_*rov 9

You may try to use OPENJSON and WITH clause (to specify columns and their types), and then search in all elements:

DECLARE @json nvarchar(max)
SET @json = '{"info":{"address":[{"town":"Belgrade"},{"town":"Paris"},{"town":"Madrid"}]}}'

SELECT Town
FROM OPENJSON(@json, '$.info.address')
WITH (
   Town nvarchar(100) '$.town'
)
WHERE Town = 'Belgrade'
Run Code Online (Sandbox Code Playgroud)

Output:

------------
Town
------------
Belgrade
Run Code Online (Sandbox Code Playgroud)

If your JSON data is in a table column, next approach is also an option:

-- Table
CREATE TABLE #Data (
   Id int,
   JsonData varchar(max)
)
INSERT INTO #Data
   (Id, JsonData)
VALUES 
   (1, N'{"info":{"address":[{"town":"Belgrade"},{"town":"Paris"},{"town":"Madrid"}]}}'),
   (2, N'{"info":{"address":[{"town":"Belgrade"},{"town":"Paris"},{"town":"Madrid"}]}}'),
   (3, N'{"info":{"address":[{"town":"Belgrade"},{"town":"Paris"},{"town":"Madrid"}]}}')


-- Statement
SELECT DISTINCT Id
FROM #Data d
CROSS APPLY (
   SELECT *
   FROM OPENJSON(d.JsonData, '$.info.address')
   WITH (
      Town nvarchar(100) '$.town'
   )
) j   
WHERE (j.Town = 'Belgrade') OR (j.Town = 'Paris')
Run Code Online (Sandbox Code Playgroud)

Output:

-------
Id
-------
1
2
3
Run Code Online (Sandbox Code Playgroud)


Pan*_*vos 8

JSON_VALUEJSON_QUERY中的路径不能接受通配符或表达式。您无法通过写入来搜索特定项目。$.info.address[?(@.town='Belgrade')]

这两个函数也返回字符串,因此您不能使用它们来提取可以查询的内容。您需要使用OPENJSON将 JSON 字符串转换为行才能查询它,例如:

declare @json nvarchar(2000)='{"info":{"address":[{"town":"Belgrade"},{"town":"Paris"},{"town":"Madrid"}]}}'

select *
from openjson(@json, '$.info.address')
with (town varchar(200) '$.town')
where town='Belgrade'
Run Code Online (Sandbox Code Playgroud)

这使用 OPENJSON 来提取数组的内容address。它将town属性提取为字段,然后在 中使用它WHERE

您可以CROSS APPLY将 OPENJSON 与表列一起使用,例如:

declare @json nvarchar(2000)='{"info":{"address":[{"town":"Belgrade"},{"town":"Paris"},{"town":"Madrid"}]}}'

DECLARE @table TABLE 
(
    id int identity primary key, 
    customer varchar(200),
    locations varchar(2000)
);

INSERT INTO @table (customer,locations)
VALUES ('AAA',@json);

SELECT *
FROM @table t CROSS APPLY OPENJSON(t.locations, '$.info.address')
                            WITH (town varchar(200) '$.town')
WHERE town='Belgrade';
Run Code Online (Sandbox Code Playgroud)