Reputation: 3090
I'm looking at about 13,000 rows in a SQL Server table, and trying to parse out certain values within one column that is stored as json.
The json column values look something like this:
..."http://www.companyurl.com","FoundedYear":"2007","Status":"Private","CompanySize":"51-200","TagLine":"We build software we believe in","Origi...
I'd like to extract the value for "CompanySize", but not all rows include this attribute. Other complicating factors:
The one rule I know for certain: the CompanySize value is always a string of unknown length that follows the varchar string "CompanySize":"
and terminates before the next ","
string.
Ideally we would have upgraded fully to SQL Server 2016 so I'd be able to take advantage of SQL Server's JSON support, but that's not the case.
Upvotes: 3
Views: 3571
Reputation: 7426
Building on @srutzky 's answer, the following solution avoids creating a UDF (although you didn't say that was a constraint, it might be useful for some).
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
Upvotes: 1
Reputation: 48806
You can do this with CHARINDEX
since you can pass it a start position, which will allow you to get the closing "
. You probably shouldn't look for ","
since if CompanySize
is the final property, it won't have the ,"
at the end of that fragment. Doing this as an Inline Table-Valued Function (iTVF) will be pretty efficient (especially since 13k rows is almost nothing), you just need to use it with either CROSS APPLY
or OUTER 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
Set up the test:
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);
Run the test:
SELECT comp.CompanySize
FROM #tmp tmp
CROSS APPLY tempdb.dbo.GetCompanySize(tmp.JSON) comp
Returns:
CompanySize
-----------
51-200
NULL
NULL
Upvotes: 4