Sta*_*ser 10 sql-server t-sql sql-server-2008-r2 replace
我正在尝试编写一个用空格替换特殊字符的查询。下面的代码有助于识别行。(字母数字字符、逗号和空格有效):
SELECT columnA
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'
Run Code Online (Sandbox Code Playgroud)
如何将替换函数集成到 select 语句中,以便结果集中除字母数字、逗号和空格之外的所有字符都替换为 ' '(空格)。这个不行:
SELECT replace(columnA,'%[^a-Z0-9, ]%',' ')
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'
Run Code Online (Sandbox Code Playgroud)
Sol*_*zky 11
如果您保证只使用美国英语字母表的 26 个字母(大写和小写版本),那么当然,您可以使用LIKE
和/或PATINDEX
使用简单的范围表示法[a-z]
(您不会使用不区分大小写的排序规则时需要使用大写的“Z”)。
但是,如果您可能会得到在 en-US 字母表中找不到但在各种代码页/VARCHAR
数据归类中可用的字符(例如Þ
= 拉丁大写字母“Thorn” = SELECT CHAR(0xDE)
),那么您可能需要将这些字符包含在字符类中:[a-z0-9, Þ]
。当然,这些额外的字符是基于每个代码页的。
此外,请注意排序规则类型(SQL Server 与 Windows)和敏感度设置(大小写、重音等敏感与不敏感)都会影响特定范围内包含的字符。例如,SQL Server 排序规则以与 Windows 排序规则相反的顺序对大写和小写字母进行排序。意思是,假设两种类型的排序规则都区分大小写,一个会做AaBb...
,另一个会做aAbB...
。效果将是a
在A-Z
其中一个的范围内,而不是另一个。并且 的范围a-Z
不会匹配二进制排序规则中的任何字符(以_BIN
或结尾_BIN2
,但不要使用_BIN
),因为 的值A
65 并且a
是 97,因此它是 97 到 65 之间的无效范围;-)。这里的例子太多了,所以我会尽快在我的博客上发布一个详细的解释(然后会用它的链接更新它)。但是,如果您打算严格只接受美国英语字符(即使您可能会从其他语言获得有效字母),那么您最好的选择可能是使用以下模式和排序规则:
LIKE '%[^A-Za-z0-9, ]%' COLLATE Latin1_General_100_BIN2
Run Code Online (Sandbox Code Playgroud)
现在,如果您正在支持NVARCHAR
数据并且可以从各种语言中获取“单词”字符,那么 T-SQL 将没有多大帮助,因为它没有真正的方法来区分这些东西。在这种情况下,您应该使用正则表达式 (RegEx) —— 特别是Replace
方法/函数 —— 而这些只能通过 SQLCLR 获得。下面显示了替换几个“特殊”字符的示例,但保留所有至少一种语言的有效字母:
LIKE '%[^A-Za-z0-9, ]%' COLLATE Latin1_General_100_BIN2
Run Code Online (Sandbox Code Playgroud)
返回:
DECLARE @Test NVARCHAR(500);
SET @Test = N'this$is%a<>TEST,;to}??strip?????¶out_ç_ƒ? special-?-?-chars-?-?-?-B';
SELECT SQL#.RegEx_Replace4k(@Test, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL);
Run Code Online (Sandbox Code Playgroud)
RegEx 表达式的意思是:
\W
= 一个正则表达式“escape”,意思是“任何非单词字符”\p{Pc}
=“标点符号,连接符”的 Unicode“类别”(匹配仅需要此“类别”,因为\W
转义特别排除了此“类别” )-[,]
= 类减法(这需要从匹配中排除逗号作为“特殊”,因为它们包含在\W
转义中)您可以通过发出以下命令来更新表:
this is a TEST, to strip out ç ƒ special ? ? chars ? ? ? B
Run Code Online (Sandbox Code Playgroud)
请注意,对于这些示例,我使用了我创建的 SQLCLR 函数的免费版SQL#库中提供的两个函数(但同样,这些都是免费的)。另请注意,由于使用NVARCHAR(4000)
而不是NVARCHAR(MAX)
参数类型,我使用了更快的“4k”版本。如果您的数据正在使用NVARCHAR(MAX)
,则只需从函数名称中删除“4k”即可。
另请参阅:
我有一个帖子在这里做了类似的事情。
基本上,我使用递归 CTE 一次又一次地循环替换一个“坏”字符。我正在使用 STUFF 去除 1 个字符(尽管您可以用它来替换一个空格)和 PATINDEX 来查找我要删除的字符的位置。你可以稍微修改它来做你正在寻找的东西。然而,它创建了一个“好”列表,它实际上并没有更新现有列表。
DECLARE @Pattern varchar(50) = '%[^A-Za-z0-9, ]%';
WITH FixBadChars AS (SELECT StringToFix, StringToFix AS FixedString, 1 AS MyCounter, Id
FROM BadStringList
UNION ALL
SELECT StringToFix, Stuff(FixedString, PatIndex(@Pattern,
FixedString COLLATE Latin1_General_BIN2), 1, ' ') AS FixedString,
MyCounter + 1, Id
FROM FixBadChars
WHERE FixedString COLLATE Latin1_General_BIN2 LIKE @Pattern)
SELECT StringToFix, FixedString, MyCounter, Id
FROM FixBadChars
WHERE MyCounter =
(SELECT MAX(MyCounter)
FROM FixBadChars Fixed
WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);
Run Code Online (Sandbox Code Playgroud)
您应该能够修改底部以进行更新而不仅仅是查询,但我实际上还没有尝试过。我相当确定它看起来像这样:
UPDATE FixBadChars
SET StringToFix = FixedString
WHERE MyCounter =
(SELECT MAX(MyCounter)
FROM FixBadChars Fixed
WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);
Run Code Online (Sandbox Code Playgroud)
至于可扩展性,我在 30 秒内返回了大约 170k 行清理过的行。再次不确定是否进行更新,但这是在我的笔记本电脑上进行的,只有 6GB 内存,速度相当慢。
归档时间: |
|
查看次数: |
109764 次 |
最近记录: |