如何在SQL Server中解析复杂的字符串

col*_*s91 2 sql sql-server stored-procedures

我试图找出解析在SQL Server中存储为字符串的复杂JSON对象的最佳方法.

我的表有以下信息:

LogID      |    Content
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
55271413   |    {"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218912","CarrierScac":"XYZ","Latitude":33.595555,"Longitude":-85.854722,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}
55271414   |    {"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218944","CarrierScac":"XYZ","Latitude":37.996666,"Longitude":-78.314444,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}
55271415   |    {"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5219079","CarrierScac":"YZB","Latitude":34.027500,"Longitude":-117.522222,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}
55271416   |    {"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5219020","CarrierScac":"XYZ","Latitude":37.754722,"Longitude":-121.144166,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}
55271417   |    {"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218911","CarrierScac":"XYZ","Latitude":40.585833,"Longitude":-91.425000,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}
55271418   |    {"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218785","CarrierScac":"XYZ","Latitude":30.747500,"Longitude":-85.270277,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}
55271426   |    {"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5219044","CarrierScac":"XYZ","Latitude":33.598333,"Longitude":-97.936388,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}
Run Code Online (Sandbox Code Playgroud)

我正在尝试解析每个字符串并将其放在一个新列中,其中JSON属性的名称作为列名,相应的值作为行值.

例如,以下是我在下面为每行寻找的结果:

LogID     |  LicensePlate  |  FreightHaulerProviderXId  |  FreightProviderReferenceNumber  |  CarrierScac  |  Latitude  |  Longitude  |  StreetAddress1  |  StreetAddress2  |  City  |  State  |  PostalCode  |  Country
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
55271413  |                |  ABC                       |  5218912                         |  XYZ          |  33.595555 |  -85.854722 |                  |                  |        |         |              |                 
Run Code Online (Sandbox Code Playgroud)

我尝试使用一些非常糟糕的SQL逻辑来解析它.基本上我查找整个字符串,获取子字符串,然后手动分配列名.对于可伸缩性和性能而言,这不是一个非常好的解决方案.

SELECT DISTINCT
    SUBSTRING(lcon.Content, CHARINDEX('CarrierScac', lcon.Content)+14, CHARINDEX('City',lcon.Content) - CHARINDEX('CarrierScac', lcon.Content) + Len('City')-21) as 'CarrierScac',
    SUBSTRING(lcon.Content, CHARINDEX('Latitude', lcon.Content)+10, CHARINDEX('Longitude',lcon.Content) - CHARINDEX('Latitude', lcon.Content) + Len('Longitude')-21) as 'Latitude',
    SUBSTRING(lcon.Content, CHARINDEX('Longitude', lcon.Content)+11, CHARINDEX('PositionEventType',lcon.Content) - CHARINDEX('Longitude', lcon.Content) + Len('"PositionEventType')-31) as 'Longitude'
FROM
    acg.LogContext lcon
WHERE
    lcon.Content LIKE '%XYZ%'
Run Code Online (Sandbox Code Playgroud)

任何帮助都会受到赞赏,因为即使在研究了一天中更好的一半技术后,我似乎也完全被困住了.

谢谢!

Joh*_*tti 7

借助解析函数和两个交叉应用...

Declare @YourTable table (LogID int,Content varchar(max))
Insert Into @YourTable values
(55271413,'{"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218912","CarrierScac":"XYZ","Latitude":33.595555,"Longitude":-85.854722,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}'),
(55271414,'{"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218944","CarrierScac":"XYZ","Latitude":37.996666,"Longitude":-78.314444,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}'),
(55271415,'{"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5219079","CarrierScac":"YZB","Latitude":34.027500,"Longitude":-117.522222,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}'),
(55271416,'{"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5219020","CarrierScac":"XYZ","Latitude":37.754722,"Longitude":-121.144166,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}'),
(55271417,'{"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218911","CarrierScac":"XYZ","Latitude":40.585833,"Longitude":-91.425000,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}'),
(55271418,'{"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5218785","CarrierScac":"XYZ","Latitude":30.747500,"Longitude":-85.270277,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}'),
(55271426,'{"LicensePlate":"","FreightHaulerProviderXId":"ABC","FreightProviderReferenceNumber":"5219044","CarrierScac":"XYZ","Latitude":33.598333,"Longitude":-97.936388,"StreetAddress1":"","StreetAddress2":"","City":"","State":"","PostalCode":"","Country":""}')


Select LogID
      ,LicensePlate = max(case when Item='LicensePlate' then Value else null end)
      ,FreightHaulerProviderXId = max(case when Item='FreightHaulerProviderXId' then Value else null end)
      ,FreightProviderReferenceNumber = max(case when Item='FreightProviderReferenceNumber' then Value else null end)
      ,CarrierScac = max(case when Item='CarrierScac' then Value else null end) 
      ,Latitude = max(case when Item='Latitude' then Value else null end)
      ,Longitude = max(case when Item='Longitude' then Value else null end)
      ,StreetAddress1 = max(case when Item='StreetAddress1' then Value else null end)
      ,StreetAddress2 = max(case when Item='StreetAddress2' then Value else null end)
      ,City = max(case when Item='City' then Value else null end)
      ,State = max(case when Item='State' then Value else null end)
      ,PostalCode = max(case when Item='PostalCode' then Value else null end)
      ,Country = max(case when Item='Country' then Value else null end)
 From ( 
        Select LogID
              ,Item  = max(case when RetSeq=1 then RetVal else null end)
              ,Value = max(case when RetSeq=2 then RetVal else null end)
        From (
                Select A.LogID
                      ,Grp = B.RetSeq
                      ,C.*
                From  @YourTable A
                Cross Apply (Select RetSeq,RetVal=Replace(Replace(Replace(RetVal,'"',''),'{',''),'}','') From [dbo].[udf-Str-Parse](A.Content,',') ) B
                Cross Apply (Select * From [dbo].[udf-Str-Parse](B.RetVal,':') ) C
            ) N Group By LogID,Grp
      ) F
 Group By LogID
Run Code Online (Sandbox Code Playgroud)

返回

在此输入图像描述


UDF如果需要的话

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From (Select x = Cast('<x>'+ Replace(@String,@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
Run Code Online (Sandbox Code Playgroud)