简体   繁体   中英

Extracting specific value from large string SQL

I've used a combination of CHARINDEX and SUBSTRING but can't get it working.

I get passed a variable in SQL that contains a lot of text but has an email in it. I need to extract the email value.

I have to use SQL 2008.

I'm trying to extract the value between "EmailAddress":" and ",

An example string is here:

{  "Type":test,
   "Admin":test,
   "User":{
      "UserID":"16959191",
      "FirstName":"Test",
      "Surname":"Testa",
      "EmailAddress":"Test.Test@test.com",
      "Address":"Test"
}
}

Assuming you can't upgrade to 2016 or higher, you can use a combination of substring and charindex .
I've used a common table expression to make it less cumbersome, but you don't have to.

DECLARE @json varchar(4000) = '{  "Type":test,
   "Admin":test,
   "User":{
      "UserID":"16959191",
      "FirstName":"Test",
      "Surname":"Testa",
      "EmailAddress":"Test.Test@test.com",
      "Address":"Test"
}
}';

WITH CTE AS
(
    SELECT @Json as Json,
    CHARINDEX('"EmailAddress":', @json) + LEN('"EmailAddress":') As StartIndex
)

SELECT SUBSTRING(Json, StartIndex, CHARINDEX(',', json, StartIndex) - StartIndex)
FROM CTE

Result: "Test.Test@test.com"

The first hint is: Move to v2016 if possible to use JSON support natively. v2008 is absolutely outdated...

The second hint is: Any string action (and all my approaches below will need some string actions too), will suffer from forbidden characters, unexpected blanks or any other surprise you might find within your data.

Try it like this:

First I create a mockup scenario to simulate your issue

DECLARE @tbl TABLE(ID INT IDENTITY,YourJson NVARCHAR(MAX));
INSERT INTO @tbl VALUES
 (N'{  "Type":"test1",
   "Admin":"test1",
   "User":{
      "UserID":"16959191",
      "FirstName":"Test1",
      "Surname":"Test1a",
      "EmailAddress":"Test1.Test1@test.com",
      "Address":"Test1"
      }
}')
,(N'{  "Type":"test2",
   "Admin":"test2",
   "User":{
      "UserID":"16959191",
      "FirstName":"Test2",
      "Surname":"Test2a",
      "EmailAddress":"Test2.Test2@test.com",
      "Address":"Test2"
      }
}');

--Starting with v2016 there is JSON support

SELECT JSON_VALUE(t.YourJson, '$.User.EmailAddress')
FROM @tbl t

--String-methods --use CHARINDEX AND SUBSTRING

DECLARE @FirstBorder NVARCHAR(MAX)='"EMailAddress":';
DECLARE @SecondBorder NVARCHAR(MAX)='",';

SELECT t.*
      ,A.Pos1
      ,B.Pos2
      ,SUBSTRING(t.YourJson,A.Pos1,B.Pos2 - A.Pos1) AS ExtractedEMail
FROM @tbl t
OUTER APPLY(SELECT CHARINDEX(@FirstBorder,t.YourJson)+LEN(@FirstBorder)) A(Pos1)
OUTER APPLY(SELECT CHARINDEX(@SecondBorder,t.YourJson,A.Pos1)) B(Pos2);

--use a XML trick

SELECT CAST('<x>' + REPLACE(REPLACE((SELECT t.YourJson AS [*] FOR XML PATH('')),'"EmailAddress":','<mailAddress value='),',',' />') + '</x>' AS XML)
      .value('(/x/mailAddress/@value)[1]','nvarchar(max)')
FROM @tbl t

Some explanations:

  • JSON-support will parse the value directly from a JSON path.
  • For CHARINDEX AND SUBSTRING I use APPLY . The advantage is, that you can use the computed positions like a variable. No need to repeat the CHARINDEX statements over and over.
  • The XML approach will transform your JSON to a rather strange and ugly XML. The only sensefull element is <mailAddress> with an attribute value . We can use the native XML method .value() to retrieve the value you are asking for:

An intermediate XML looks like this:

<x>{  "Type":"test1" /&gt;
       "Admin":"test1" /&gt;
       "User":{
          "UserID":"16959191" /&gt;
          "FirstName":"Test1" /&gt;
          "Surname":"Test1a" /&gt;
          <mailAddress value="Test1.Test1@test.com" />
          "Address":"Test1"
          }
    }</x>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM