Sql server 使用正则表达式(或类似表达式)更新字段
在我的表中有一个名为Url的字段,如下所示:Sql server 使用正则表达式(或类似表达式)更新字段,sql-server,regex,database,sql-server-2008,tsql,Sql Server,Regex,Database,Sql Server 2008,Tsql,在我的表中有一个名为Url的字段,如下所示: /MyServer/MyPage?Param=XXX 我需要运行一个脚本,以便将该字段从XXX更新为YYY。我确实有规则说明YYY与XXX对应的是什么,问题是我不知道如何只更新参数为exacltyparam的字段,而不知道如何更新其他字段 因此,这些将是更新: /MyServer/MyPage?Param=XXX ==> /MyServer/MyPage?Param=XXX /MyServer/MyOtherPage?Par
/MyServer/MyPage?Param=XXX
我需要运行一个脚本,以便将该字段从
XXX
更新为YYY
。我确实有规则说明YYY与XXX对应的是什么,问题是我不知道如何只更新参数为exacltyparam
的字段,而不知道如何更新其他字段
因此,这些将是更新:
/MyServer/MyPage?Param=XXX ==> /MyServer/MyPage?Param=XXX
/MyServer/MyOtherPage?Param=AAA ==> /MyServer/MyOtherPage?Param=BBB
/MyServer/MyOtherPage?Param2=JJJ ==> /MyServer/MyOtherPage?Param2=JJJ
(last row no changes since it is not param)
我说清楚了吗
编辑:我有一个辅助表,对应于XXX
YYY
。请记住,XXX
只是一个例子。实际上,参数是一个整数,因此参数值的长度是可变的
declare @T table
(
Col varchar(50)
)
insert into @T values
('/MyServer/MyPage?Param=XXX'),
('/MyServer/MyOtherPage?Param=AAA'),
('/MyServer/MyOtherPage?Param2=JJJ')
declare @P table
(
ID int,
P1 varchar(50),
P2 varchar(50)
)
insert into @P values
(1, 'AAA', 'BBB'),
(2, 'XXX', 'YYY')
update T
set Col = left(T.Col, len(T.Col)-len(P.P1))+P.P2
from @T as T
inner join @P as P
on right(T.Col, len(P.P1)+6) = 'Param='+P.P1
where P.ID = 1
select *
from @T
结果:
Col
--------------------------------------------------
/MyServer/MyPage?Param=XXX
/MyServer/MyOtherPage?Param=BBB
/MyServer/MyOtherPage?Param2=JJJ
url
------------------------------------------------
/MyServer/MyPage?Param=YYY&Param2=JJJ
/MyServer/MyPage?Param2=XXX
/MyServer/MyOtherPage?Param2=JJJ&Param=BBB
/MyServer/MyOtherPage?Param=AAAA
/MyServer/MyOtherPage?Param=AAAA&Param2=JJJ
这解决了Mikael的顾虑,即
AAA
,XXX
等可能出现在URL中。它还处理参数不是URL中最后一个参数的情况
DECLARE @URLs TABLE (URL VARCHAR(2000));
INSERT @URLs SELECT '/MyServer/MyPage?Param=XXX'
UNION ALL SELECT '/MyServer/MyOtherPage?Param=AAA'
UNION ALL SELECT '/MyServerAAA/MyOtherPage?Param=AAA'
UNION ALL SELECT '/MyServer/MyOtherPage?Param2=JJJ'
UNION ALL SELECT '/MyServer/MyOtherPage?Param=AAA&Param2=JJJ'
UNION ALL SELECT '/MyServer/MyOtherPage?Param2=AAA&Param=AAA';
DECLARE @rules TABLE(pSrc VARCHAR(32), pDest VARCHAR(32));
INSERT @rules SELECT 'XXX', 'YYY'
UNION ALL SELECT 'AAA', 'BBB'
UNION ALL SELECT 'JJJ', 'KKK';
;WITH src AS
(
SELECT URL,
pre = LEFT(URL, CHARINDEX('?', URL)-1),
post = SUBSTRING(URL, CHARINDEX('?', URL), 2000)
FROM @URLs
), sub AS
(
SELECT src.URL, src.pre, src.post, r.pSrc, r.pDest,
i = PATINDEX('%[?&]Param=' + r.pSrc + '&%', post + '&')
FROM src INNER JOIN @Rules AS r
ON src.post + '&' LIKE '%[?&]Param=' + r.pSrc + '&%'
)
UPDATE u SET URL = pre + STUFF(post, i+7, LEN(pSrc), pDest)
FROM @URLs AS u INNER JOIN sub ON u.URL = sub.URL;
SELECT * FROM @URLs;
结果:
URL
--------------------------------
/MyServer/MyPage?Param=YYY
/MyServer/MyOtherPage?Param=BBB
/MyServerAAA/MyOtherPage?Param=BBB
/MyServer/MyOtherPage?Param2=JJJ
/MyServer/MyOtherPage?Param=BBB&Param2=JJJ
/MyServer/MyOtherPage?Param2=AAA&Param=BBB
/MyServer/MyPage?Param=YYY
/MyServer/MyOtherPage?Param=BBB
/MyServer222/MyOtherPage?Param=BBB
/MyServer222/MyOtherPage?Param=bbb
/MyServer/MyOtherPage?Param=BBB&Param2=333
/MyServer/MyOtherPage?Param=bbb&Param2=333
/MyServer/MyOtherPage?Param2=222&Param=BBB
添加后续问题的文档链接。是的,STUFF
是一个函数
这里有一个
replace()
方法
编辑:增加了灵活性
declare @myURLs table(url varchar(1000))
insert into @myURLs values ('/MyServer/MyPage?Param=XXX&Param2=JJJ'); --should update
insert into @myURLs values ('/MyServer/MyPage?Param2=XXX'); --should not update
insert into @myURLs values ('/MyServer/MyOtherPage?Param2=JJJ&Param=AAA'); --should update
insert into @myURLs values ('/MyServer/MyOtherPage?Param=AAAA'); --should not update
insert into @myURLs values ('/MyServer/MyOtherPage?Param=AAAA&Param2=JJJ'); --should not update
declare @replacements table(targetStr varchar(80), replStr varchar(80));
insert into @replacements values ('Param=AAA','Param=BBB');
insert into @replacements values ('Param=XXX','Param=YYY');
-- ANSI-92 syntax
update u
set url=REPLACE(url,r.targetStr,r.replStr)
from @myURLs u
inner join @replacements r on
(PATINDEX('%[?&]'+r.targetStr,url)>0
or PATINDEX('%[?&]'+r.targetStr+'[?&]%',url) > 0);
SELECT *
FROM @myURLs;
结果:
Col
--------------------------------------------------
/MyServer/MyPage?Param=XXX
/MyServer/MyOtherPage?Param=BBB
/MyServer/MyOtherPage?Param2=JJJ
url
------------------------------------------------
/MyServer/MyPage?Param=YYY&Param2=JJJ
/MyServer/MyPage?Param2=XXX
/MyServer/MyOtherPage?Param2=JJJ&Param=BBB
/MyServer/MyOtherPage?Param=AAAA
/MyServer/MyOtherPage?Param=AAAA&Param2=JJJ
只是为了好玩,因为最初的问题确实提到了正则表达式,我想我会给出一个使用正则表达式的例子。是的,这确实需要SQLCLR,不是每个人都可以或将使用它,但这是一个选项 本例确实使用了一个现有的SQLCLR库,我是该库的作者,但是正则表达式函数(只有3个例外)是免费的 该示例使用Aaron Bertrand答案中的示例URL和规则表变量,但将“source”字符串更改为数字(因为这是原始请求,正则表达式在这方面是特定的),并且我添加了一个测试用例以显示字符串“222”与“2222”的任何部分都不匹配
公平地说,严格的T-SQL解决方案并没有测试性能,而是测试功能性和灵活性。哪种解决方案性能更好,必须在您的服务器上进行测试。第一行是否表示在“after”值的末尾有YYY?另外,您使用的是什么版本的SQL Server?我使用的是SQL Server 2008,是的,要替换的字符串总是在+1奇怪的时间末尾。我使用了
STUFF
,因为我认为如果参数实际上不在字符串的末尾,则更容易调整。@AaronBertrand-是的,STUFF很好。我认为您应该在回答中使用REVERSE进行一些计算,以找到字符串的最后一个匹配项。我使用了一个稍微不同的路径,最终结果相同。如果Param2=AAA,这将错误地将其更改为Param2=BBB。另外,Param=AAAA变成Param=ABBB。@JohnDewey谢谢,我想已经修复了。如果参数也是URL的一部分,这可能会给您带来麻烦/MyAAAServer/MyOtherPage?Param=AAA
变成/MyBBBServer/MyOtherPage?Param=AAA
。谢谢@Mikael,我想我已经解决了。嗯,是的,再次感谢。很明显,我在个人和联合之间进行了交换。@AaronBertrand-我认为如果您将硬编码的参数=
从子移动到@rules
,并将I+7
替换为I+1
,您将获得更大的灵活性。通过这种方式,@rules
可以混合其他参数,例如param2=CCCC
=>param2=MM
等。为什么要在1=1时加入,然后在where子句中添加加入加入条件?我知道这是合法的,有效的,但这是一个没有明显目的的附加条款。我想问一下replacements表中identity列的用途,但我对join更感兴趣。为什么会出现while循环?你的更新不应该一下子影响整个场景吗?@AaronBertrand-谢谢你指出这些。WHILE
和id
是上一次迭代遗留下来的行李,现在已经过时了。更简单的查询被更新了。哦,太恐怖了!非ANSI连接?老实说,我更喜欢1=1的答案-/@AaronBertrand——逻辑上它相当于1=1,但我认为是旧的ANSI-86标准。但是为什么不在pat索引上进行内部连接呢?IMHO,旧的样式并不是永久化和鼓励的好做法,因为它太容易意外地进入笛卡尔坐标系,而且更改为外部联接也会带来痛苦(因为*=/=*已被弃用)。