SQL - 字符串操作

SQL - String Manipulation

上下文: 我在 SQL 服务器中有一个视图可以跟踪用户在 运行 SSRS 报告 (ReportServer.dbo.ExecutionLog) 时输入的参数。大约 50 个报告参数在具有 ntext 数据类型的单个列中保存为字符串。我想为每个参数将这个单列分成多列。

详情: 我这样查询报告参数:

SELECT ReportID, [Parameters]
FROM ReportServer.dbo.ExecutionLog
WHERE ReportID in (N'redacted')
and [Status] in (N'rsSuccess')
ORDER BY TimeEnd DESC

下面是结果的一小部分:

alpha=123&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM

问题:

我怎样才能得到这样的结果:

SQL Server 2017 Python 友好。在这种情况下,Python 是否是一种更好的语言,仅用于解析目的?

我看过类似的主题here, here & 。参数是动态的,因此通过 SQL 涉及计算字符的字符串函数进行解析不适用。这个问题不仅与我有关,还与更多人有关,因为有很多人在使用 SSRS。以更易于理解的方式跟踪和格式化参数对所有 SSRS 用户都很有价值。

在 & 字符处拆分字符串。

在等号上进一步将每一行分成两列。

在第二列中,将 %2C 替换为逗号字符,将 %2F 替换为正斜杠字符,依此类推,根据需要进行任何其他替换。

使用动态枢轴以您想要的格式查询以上内容。

这是使用内置 STRING_SPLIT 的方法。我只是不确定日期之后的内容的逻辑是什么,所以我会丢弃它,但我留给你决定。

DEMO

declare @table table (ReportID int identity(1,1),  [Parameters] varchar(8000))
insert into @table
values
('alpha=123&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM')
,('alpha=457893&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM')

select 
    ReportID
    ,[Parameters]
    ,alpha = max(iif(value like 'alpha%',substring(value,charindex('=',value) + 1,99),null))
    ,bravo = max(iif(value like 'bravo%',substring(value,charindex('=',value) + 1,99),null))
    ,charlie = max(iif(value like 'charlie%',substring(value,charindex('=',value) + 1,99),null))
    ,delta = max(iif(value like 'delta%',substring(value,charindex('=',value) + 1,99),null))
    ,echo = max(iif(value like 'echo%',substring(value,charindex('=',value) + 1,99),null))
    ,foxtrot = max(iif(value like 'foxtrot%',substring(value,charindex('=',value) + 1,99),null))
from @table
cross apply string_split(replace(replace([Parameters],'%2C',','),'%2F','/'),'&')
group by ReportID, [Parameters]

或者,如果它们不是静态的,您可以使用动态枢轴。需要一些修改才能使您的列按正确的顺序排列。

DEMO

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(substring([value],0,charindex('=',[value]))) 
                from myTable
                cross apply string_split(replace(replace([Parameters],'%2C',','),'%2F','/'),'&')
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


select @cols

set @query = 'SELECT ReportID, ' + @cols + ' from 
            (
                select ReportID
                    , ColName = substring([value],0,charindex(''='',[value]))
                    , ColVal = substring([value],charindex(''='',[value]) + 1,99)
                from myTable
                cross apply string_split(replace(replace([Parameters],''%2C'','',''),''%2F'',''/''),''&'')
           ) x
            pivot 
            (
                 max(ColVal)
                for ColName in (' + @cols + ')
            ) p '

execute(@query)

这是一个以大量替换开始的方法。
要url-解码字符串并将其转换为XML类型。

然后它使用 XML 函数获取列的值。

示例片段:

declare @Table table ([Parameters] varchar(200));

insert into @Table ([Parameters]) values
('alpha=123&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM');

select 
x.query('/x[key="alpha"]/val').value('.', 'int') as alpha,
x.query('/x[key="bravo"]/val').value('.', 'varchar(30)') as bravo,
x.query('/x[key="charlie"]/val').value('.', 'varchar(30)') as charlie,
x.query('/x[key="delta"]/val').value('.', 'varchar(30)') as delta,
convert(date, x.query('/x[key="echo"]/val').value('.', 'varchar(30)'), 103)as echo,
convert(date, x.query('/x[key="foxtrot"]/val').value('.', 'varchar(30)'), 103) as foxtrot
from @Table
cross apply (select cast('<x><key>'+ 
  replace(replace(replace(replace(replace(
    replace([Parameters], 
       '%2C',','), 
       '%2F','/'), 
       '%20',' '), 
       '%3A',':'),
       '=','</key><val>'), 
       '&','</val></x><x><key>') 
     +'</val></x>' as XML) as x) ca

测试 db<>fiddle here