【问题标题】:SQL Replace ASCII With LoopSQL 用循环替换 ASCII
【发布时间】:2011-02-14 20:28:23
【问题描述】:

我目前正在尝试在 SQL 中创建一个存储过程。

但我被困在某事上。 我想用 nvarchar 值从几列中检索数据,但我想替换所有扩展的 ASCII 值(来自 ASCII 128 及更高版本的值)

我知道可以使用 Replace 函数来实现,但是否也可以使用循环或类似的东西来做到这一点,否则我必须为 ASCII 值 126 到 255 创建替换函数。 我想可能有更简单的方法可以做到这一点,有人有什么想法吗?

使用:Microsoft SQL Server 2008

【问题讨论】:

  • 一个小修正:实际上它是 128,它是扩展 ASCII 码的起始值,而不是 126。
  • 感谢您的关注,已更改:)
  • 请换成什么?空间?空字符串?
  • 什么数据库? “SQL”不是数据库的名称。
  • @martin 这就是我的意思,但我想不出更好的术语('rdbms')。我讨厌“SQL”== MS 的假设。 :)

标签: sql sql-server-2008 stored-procedures ascii


【解决方案1】:

我看到 Cade Roux 在我编写实际代码时发布了一些一般性指导。

创建映射表。如果您不需要重音字符替换,则可以不用这样的表。按要求填写,我以200228和131-134为例。

select number,
 char(number) original,
 case
 when number < 128 then char(number)
 when number = 200 then 'E'
 when number = 228 or number in (131,132,133,134) then 'a'
 else ' '
 end replacement
into charmap
from master..spt_values
where type='p' and number between 0 and 255

测试表

create table tvc (id int identity, vc nvarchar(100))
insert tvc select 'abcdef'
insert tvc select 'abätest'
insert tvc select 'abÔÖÕüûýèend'

替换查询

update tvc
SET vc = (select cast
    ((select m.replacement+''
    from master..spt_values v
    inner join charmap m on m.original=substring(tvc.vc,v.number,1) collate French_BIN
    where v.type='P' and v.number between 1 and len(tvc.vc)
    order by v.number
    for xml path(''), type) as varchar(max)))

注意事项:

  • 对直到 nvarchar(2047) 的列使用了一次 spt_values。您可以将它们链接在一起以获得更长的列(最大)
  • collat​​e French_BIN 是为了防止 A 匹配任何带重音的 A 等
  • xml type 和转换为 varchar(max) 的复杂包装器用于防止空格变成&amp;#x20;


不使用charmap并且不需要对重音字符进行特殊处理:
update tvc
set vc = (select cast
    ((select case when ascii(substring(tvc.vc,v.number,1)) < 128
        then substring(tvc.vc,v.number,1)
        else ' ' end
    from master..spt_values v
    where v.type='P' and v.number between 1 and len(tvc.vc)
    order by v.number
    for xml path(''), type) as varchar(max))) r(new)

【讨论】:

  • 谢谢,这对解决我的问题很有帮助!
【解决方案2】:
【解决方案3】:

使用正则表达式:)

只需列出您在模式中实际需要提取的所有符号。

类似[a-zA-Z0-9]*

【讨论】:

  • 你的意思是使用 Replace(Replace(Replace...?
  • @SterAllures - 我认为您需要使用 CLRREGEX 替换。我认为有可能为“不在集合字符代码 0 -128 中的单个字符”提供一个正则表达式。
【解决方案4】:

否则我必须为 ASCII 值 126 到 255 创建替换函数

比这更糟糕。 nvarchar 类型将其数据存储为 UCS-2(一种 Unicode 格式),因此您需要替换数千个可能的字符:

更好的选择是将您想要的字符列入白名单,而不是将您不想要的字符列入黑名单。这是一个 SQL 脚本,它将返回标准 ASCII 集 (modified from a Microsoft example) 内的 Unicode 字符串中的所有字符。它将用一个空格替换其他字符。在 'ö' 字符的情况下,它将字符替换为 'o'(作为示例)。

 DECLARE @position int, @nstring nvarchar(9), @nch nchar, @output nvarchar(9)
 SET @position = 1
 SET @nstring = N'København'
 SET @output = ''

 WHILE @position <= LEN(@nstring)
 BEGIN
     SELECT @nch = SUBSTRING(@nstring, @position, 1)

     IF UNICODE(@nch) < 128
         SELECT @output = @output + @nch
     ELSE IF @nch = 'ö'
         SELECT @output = @output + 'o'
     ELSE
         SELECT @output = @output + ' '

     SELECT @position = @position + 1
 END

 SELECT @output
 GO

要处理您的最新评论(用不带重音的 ASCII 变体替换重音字符),您需要添加许多额外的条件:

 ELSE IF @nch = 'ö'
     SELECT @output = @output + 'o'

我认为 MSSQL 没有内置的函数来执行此操作。

【讨论】:

  • 如果我要使用它,我是否也可以将它用作以后的过滤器,所以我创建了它,这会调用另一个 SP 来过滤掉这些值。所以在nstring变量中我必须使用我从另一个SP得到的结果,我可以这样做(调用一个SP并将它用作变量来过滤掉扩展的ASCII码)?
  • 是的。有几种方法可以从存储过程中获取值。可能最好的方法是使用输出变量。查看此页面上的输出变量部分:sqlteam.com/article/stored-procedures-returning-data
  • 不,你不会。由于所需的最终结果是 ASCII 集 (0-127),因此只需 VARCHAR 并进行 VARCHAR 替换。
  • @Ant 使用 Datalength 是错误的。对于 len 6 的 nvarchar,它将尝试子串最多 12。
  • @cyberwiki:是的。但是,这种方法不需要演员表。
【解决方案5】:

还可以通过 unpivot 运行字符串以生成字符行,与转换表进行映射(现在是每行操作)并重新旋转以将行重新组合成列。

Jeff Modem 介绍了使用计数表来实现此技术:

http://www.sqlservercentral.com/articles/T-SQL/62867/

cyberkiwi 在他的回答中几乎完全为您实现了它:

SQL Replace ASCII With Loop

【讨论】:

    猜你喜欢
    • 2016-10-11
    • 2019-04-04
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多