使用SQL解析JSON:如何在JSON对象中提取记录?

时间:2015-07-29 19:05:03

标签: sql-server json string tsql

我正在查看SQL Server表中的大约13,000行,并尝试解析存储为json的一列中的某些值。

json列值看起来像这样:

..."http://www.companyurl.com","FoundedYear":"2007","Status":"Private","CompanySize":"51-200","TagLine":"We build software we believe in","Origi...

我想提取“CompanySize”的值,但并非所有行都包含此属性。其他复杂因素:

  • 我不确定“CompanySize”参数中有多少可能的值。
  • “CompanySize”并不总是后跟“TagLine”参数。

我确定知道的一条规则:CompanySize值始终是一个未知长度的字符串,它跟在varchar字符串"CompanySize":"之后,并在下一个","字符串之前终止。

理想情况下,我们会完全升级到SQL Server 2016,因此我可以利用SQL Server's JSON support,但事实并非如此。

2 个答案:

答案 0 :(得分:4)

您可以使用CHARINDEX执行此操作,因为您可以将其传递给开始位置,这样您就可以获得结束"。您可能不应该查找",",因为如果CompanySize是最终属性,则它不会在该片段的末尾有,"。这样做作为内联表值函数(iTVF)将非常有效(特别是因为13k行几乎没有),您只需要将它与CROSS APPLYOUTER APPLY一起使用:

USE [tempdb];
GO

CREATE FUNCTION dbo.GetCompanySize(@JSON NVARCHAR(MAX))
RETURNS TABLE
AS RETURN

WITH SearchStart AS
(
  SELECT '"CompanySize":"' AS [Fragment]
), Search AS
(
  SELECT CHARINDEX(ss.Fragment, @JSON) AS [Start],
         LEN(ss.Fragment) AS [FragmentLength]
  FROM   SearchStart ss
)
SELECT CASE Search.Start
         WHEN 0 THEN NULL
         ELSE SUBSTRING(@JSON,
                        (Search.Start + Search.FragmentLength),
                        CHARINDEX('"',
                                  @JSON,
                                  Search.Start + Search.FragmentLength
                                 ) - (Search.Start + Search.FragmentLength)
                       )
       END AS [CompanySize]
FROM Search;
GO

设置测试:

CREATE TABLE #tmp (JSON NVARCHAR(MAX));

INSERT INTO #tmp (JSON) VALUES
('"http://www.companyurl.com","FoundedYear":"2007","Status":"Private","CompanySize":"51-200","TagLine":"We build software we believe in","Origi..');
INSERT INTO #tmp (JSON) VALUES
('"http://www.companyurl.com","FoundedYear":"2009","Status":"Public","TagLine":"We build software we believe in","Origi..');
INSERT INTO #tmp (JSON) VALUES (NULL);

运行测试:

SELECT comp.CompanySize
FROM   #tmp tmp
CROSS APPLY tempdb.dbo.GetCompanySize(tmp.JSON) comp

返回:

CompanySize
-----------
51-200
NULL
NULL

答案 1 :(得分:1)

在@srutzky的回答的基础上,以下解决方案避免了创建UDF(虽然您没有说这是一个约束,但它可能对某些人有用)。

select
    c.Id,
    substring(i2.jsontail, 0, i3.[length]) CompanySize
from
    Companies c cross apply
    ( select charindex('CompanySize":"', c.json) start ) i1 cross apply
    ( select substring(c.json, start + len('CompanySize":"'), len(c.json) - start ) jsontail ) i2 cross apply
    ( select charindex('"', i2.jsontail) [length] ) i3
where
    i1.[start] != 0