Sql server 2008 r2 T-SQL中的转义]和^characters;“模式”;表达式字符类

Sql server 2008 r2 T-SQL中的转义]和^characters;“模式”;表达式字符类,sql-server-2008-r2,escaping,patindex,Sql Server 2008 R2,Escaping,Patindex,我试图通过以下查询模拟MsSql Server 2008 R2中Oracle的RTRIM(表达式、字符): REVERSE( SUBSTRING( REVERSE(field), PATINDEX('%[^chars]%', REVERSE(field)), LEN(field) - PATINDEX('%[^chars]%', REVERSE(field)) + 1

我试图通过以下查询模拟MsSql Server 2008 R2中Oracle的
RTRIM(表达式、字符)

REVERSE(
        SUBSTRING(
                  REVERSE(field),
                  PATINDEX('%[^chars]%', REVERSE(field)),
                  LEN(field) - PATINDEX('%[^chars]%', REVERSE(field)) + 1
             )
       )
问题是我希望能够修剪像
]
^
这样可能需要转义的字符

我不知道怎么做。像
\]
这样的东西不起作用

我知道
ESCAPE
子句,但我不清楚它是如何工作的,顺便说一句,如果放在模式字符串后面,SqlServer会拒绝它

有趣的事实:

如果我写
%[^^]%
(希望修剪
^
),它就不起作用

如果我写
%[^^]%
它会修剪
^
,但显然也会修剪空格

不漂亮,但是

CREATE FUNCTION dbo.RTRIMCHARS(
    @input AS VARCHAR(MAX), @chars AS VARCHAR(100)
) RETURNS VARCHAR(MAX) 
AS 
BEGIN
    DECLARE @charpos BIGINT
    DECLARE @strpos BIGINT

    SET @strpos = LEN(@input)
    SET @charpos = LEN(@chars)

    IF @strpos IS NULL OR @charpos IS NULL RETURN NULL
    IF @strpos = 0 OR @charpos = 0 RETURN @input

    WHILE @strpos > 0
    BEGIN
        SET @charpos = LEN(@chars)
        WHILE @charpos > 0
        BEGIN
            IF SUBSTRING(@chars, @charpos, 1) = SUBSTRING(@input, @strpos, 1)
            BEGIN
                SET @strpos = @strpos - 1
                BREAK
            END
            ELSE
            BEGIN
                SET @charpos = @charpos - 1
            END
        END
        IF @charpos = 0 BREAK
    END
    RETURN SUBSTRING(@input, 1, @strpos)
END
用法


我在MS Connect上找到此文档:

用户使用
PATINDEX
询问
ESCAPE
子句,然后另一个用户也扩展了对
CHARINDEX
的请求

MS回答:由于无法修复而关闭票证:(

我为
LTrim
编写了自己的自定义函数:

CREATE FUNCTION LTrim_Chars (
  @BaseString varchar(2000),
  @TrimChars varchar(100)
)

RETURNS varchar(2000) AS

BEGIN

  DECLARE @TrimCharFound bit

  DECLARE @BaseStringPos int
  DECLARE @TrimCharsPos int

  DECLARE @BaseStringLen int
  DECLARE @TrimCharsLen int

  IF @BaseString IS NULL OR @TrimChars IS NULL
  BEGIN
      RETURN NULL
  END

  SET @BaseStringPos = 1

  SET @BaseStringLen = LEN(@BaseString)
  SET @TrimCharsLen = LEN(@TrimChars)

  WHILE @BaseStringPos <= @BaseStringLen
  BEGIN 

      SET @TrimCharFound = 0
      SET @TrimCharsPos = 1

      WHILE @TrimCharsPos <= @TrimCharsLen
      BEGIN     
          IF SUBSTRING(@BaseString, @BaseStringPos, 1) = SUBSTRING(@TrimChars, @TrimCharsPos, 1)
          BEGIN
              SET @TrimCharFound = 1
              BREAK
          END             
          SET @TrimCharsPos = @TrimCharsPos + 1     
      END

      IF @TrimCharFound = 0
      BEGIN
        RETURN SUBSTRING(@BaseString, @BaseStringPos, @BaseStringLen - @BaseStringPos + 1)
      END       
      SET @BaseStringPos = @BaseStringPos + 1

  END

  RETURN ''

END
CREATE FUNCTION RTrim_Chars (
  @BaseString varchar(2000),
  @TrimChars varchar(100)
)

RETURNS varchar(2000) AS

BEGIN

  RETURN REVERSE(LTrim_Chars(REVERSE(@BaseString), @TrimChars))

END
至少,我学会了一些MsSql脚本


编辑:

我添加了
NULL
检查这两个参数,以反映Oracle和Postgres的行为

不幸的是,Oracle的行为仍然略有不同:
在编写
LTRIM(string,”)
的情况下,它返回
NULL
,因为0长度的字符串类似于Oracle中的
NULL
,因此它实际上返回
LTRIM(string,NULL)
的结果,实际上是
NULL


顺便说一句,这是一个非常奇怪的情况。

这有帮助吗?问题是
]
关闭字符类。在RegExp中,您使用
\
在字符类中转义
]
。谢谢您的回答,但我已经完成了自己的一个。请检查:)您的函数似乎工作不正常:如果我调用
RTRIMCHARS('s')[PROJECT],'E')
它返回
[PROJ
@Teejay我已经修复了我的代码,使其能够按照规范工作。唉,现在它也使用了嵌套循环。-)我会投票支持你提出自己的解决方案;我只是不想让坏代码出现在我的答案中。如果你愿意,请针对你的函数做一个基准测试,我对你的发现非常感兴趣!我发现了本地
LTRIM(str)
(像我的)或本地
RTRIM(str)
(像你的)运行速度比
REVERSE(LTRIM(REVERSE(str))
快20%,尽管后者在代码可维护性方面有所提高,因为你只需要编辑一个函数。顺便说一句,我在PLSQL(Oracle)中实现了相同的函数它的响应时间与stock
LTRIM
类似。基本上,即使是本机函数也需要执行相同的操作。在
WHILE
循环中逐个字符地检查输入(以及嵌套的循环!)可能比我的建议效率低。通常情况下,我会修剪1-2个字符,因此性能下降应该是一个问题。无论如何,我会更好地检查您的函数!谢谢!请注意,我的解决方案支持
a-z
0-9
中的字符范围。这可能很方便。是的,我明白了。但它有一些基本问题…请参阅我的对您的回答进行评论是的,我理解。事实上,范围支持是我使用
PATINDEX
的一个副作用,所以这并不是故意的。
CREATE FUNCTION RTrim_Chars (
  @BaseString varchar(2000),
  @TrimChars varchar(100)
)

RETURNS varchar(2000) AS

BEGIN

  RETURN REVERSE(LTrim_Chars(REVERSE(@BaseString), @TrimChars))

END