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
的方法。我只是不确定日期之后的内容的逻辑是什么,所以我会丢弃它,但我留给你决定。
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]
或者,如果它们不是静态的,您可以使用动态枢轴。需要一些修改才能使您的列按正确的顺序排列。
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
上下文: 我在 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 &
在 & 字符处拆分字符串。
在等号上进一步将每一行分成两列。
在第二列中,将 %2C
替换为逗号字符,将 %2F
替换为正斜杠字符,依此类推,根据需要进行任何其他替换。
使用动态枢轴以您想要的格式查询以上内容。
这是使用内置 STRING_SPLIT
的方法。我只是不确定日期之后的内容的逻辑是什么,所以我会丢弃它,但我留给你决定。
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]
或者,如果它们不是静态的,您可以使用动态枢轴。需要一些修改才能使您的列按正确的顺序排列。
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