【问题标题】:What's wrong with NVARCHAR and PATINDEX?NVARCHAR 和 PATINDEX 有什么问题?
【发布时间】:2016-02-24 08:54:51
【问题描述】:

请找到我写的这个SQL函数

编辑:优化功能,就像在第一个案例中建议的那样

CREATE FUNCTION [dbo].[TL_ReplaceOldBrand]
(
    @string NVARCHAR(max),
    @BrandName NVARCHAR(50) = N'Brand',
    @BrandNameNew NVARCHAR(50) = N'NewBrand'
)
RETURNS NVARCHAR(max)
AS

BEGIN       
    DECLARE @ResultString NVARCHAR(max) = @string
    DECLARE @PossibleCharactersBegin NVARCHAR(100) = N'%[ ,.;:/?!-‘’''"(<>)' + Char(13) + Char(10) + ']'
    DECLARE @PossibleCharactersEnd NVARCHAR(100) = N'[ ,.;:/?!-‘’''"(<>)' + Char(13) + Char(10) + ']%'
    DECLARE @searchString NVARCHAR(100)

    --The brand name ONLY
    IF @ResultString = @BrandName
        SET @ResultString = REPLACE(@ResultString, @BrandName, @BrandNameNew)

    --The brand name at BEGINNING
    SET @searchString = N'' + @BrandName + @PossibleCharactersEnd
    WHILE PATINDEX(@searchString, @ResultString) > 0
    SET @ResultString = STUFF(@ResultString, PATINDEX(@searchString, @ResultString), LEN(@BrandName), @BrandNameNew)

    --The brand name BETWEEN words
    SET @searchString = N'' + @PossibleCharactersBegin + @BrandName + @PossibleCharactersEnd
    WHILE PATINDEX(@searchString, @ResultString) > 0
    SET @ResultString = STUFF(@ResultString, PATINDEX(@searchString, @ResultString) + 1, LEN(@BrandName), @BrandNameNew)

    --The brand name at the END
    SET @searchString = N'' + @PossibleCharactersBegin + @BrandName
    WHILE PATINDEX(@searchString, @ResultString) > 0
    SET @ResultString = STUFF(@ResultString, PATINDEX(@searchString, @ResultString) + 1, LEN(@BrandName), @BrandNameNew)

    RETURN @ResultString
END

当我这样使用它时就像这样:

select dbo.TL_ReplaceOldBrand(N'I want to replace, Brand by NewBrand, in a long long text which have multiple Brand occurences.', DEFAULT, DEFAULT)

没有发生替换。但是,如果我在函数定义中将所有 NVARCHAR 替换为 VARCHAR,它就可以正常工作并按照我的意愿将 Brand 替换为 NewBrand

谁能给我解释一下为什么?

为了回答这个问题,我为什么要使用 NVARCHAR 而不是 VARCHAR,这是因为该函数用于包含多种语言文本的列,这些文本带有特殊字符,例如中文、泰文或韩文

【问题讨论】:

  • 由于您的第一次搜索/替换使用的是最匹配的字符串,您认为后续搜索会做什么? IE。如果你已经通过一个字符串将每个A 替换为B,为什么你认为你会在随后的匹配中尝试找到A,并对其周围的字符进行额外的限制?
  • 一旦你过了那个点,为什么不直接使用REPLACE 而不是手动查找/替换事件。
  • REPLACE 当您没有多个可以呈现单词的情况时很好。我可以有“,Brand:”或“Brand”或“Brand-”或“Brand_”。
  • 但是如果你有更好的想法来优化这个功能,我会听取每一个解决方案。我不是 SQL Server 专家,我每天都在听,所以我在练习 ;-)
  • 也许是这样,但您的第一个查找和替换是在寻找“品牌”,周围没有任何东西,这也与所有其他情况相匹配。它正在做REPLACE 会做的事情。

标签: sql sql-server-2012


【解决方案1】:

最后,我找到了解决我的问题的替代答案

请找出我写的新函数

CREATE FUNCTION [dbo].[TL_ReplaceOldBrand]
(
    @string NVARCHAR(max),
    @BrandName VARCHAR(50) = N'Brand',
    @BrandNameNew VARCHAR(50) = N'NewBrand'
)
RETURNS NVARCHAR(max)
AS

BEGIN       
    DECLARE @ResultString VARCHAR(max) = @string
    DECLARE @NResultString NVARCHAR(max) = @string

    --REMARK: CHAR(13): Carriage Return
    --      : CHAR(10): Line Feed
    --      : CHAR(9) : Tabulation
    DECLARE @PossibleCharactersBegin VARCHAR(100) = N'%[ ,.;:/?!-‘’''"(<>)' + Char(13) + Char(10) + Char(9) + ']'
    DECLARE @PossibleCharactersEnd VARCHAR(100) = N'[ ,.;:/?!-‘’''"(<>)' + Char(13) + Char(10) + Char(9) + ']%'
    DECLARE @searchString VARCHAR(100)

    DECLARE @index int = 0

    --The brand name ONLY
    IF @NResultString = @BrandName
    BEGIN
        SET @NResultString = REPLACE(@NResultString, @BrandName, @BrandNameNew)
        SET @ResultString = CONVERT(VARCHAR(MAX), @NResultString)
    END

    --The brand name at BEGINNING
    SET @searchString = N'' + @BrandName + @PossibleCharactersEnd   
    SET @index = PATINDEX(@searchString, @ResultString)
    WHILE @index > 0
    BEGIN
        SET @NResultString = STUFF(@NResultString, @index, LEN(@BrandName), @BrandNameNew)
        SET @ResultString = @NResultString

        SET @index = PATINDEX(@searchString, @ResultString)
    END

    --The brand name BETWEEN words
    SET @searchString = N'' + @PossibleCharactersBegin + @BrandName + @PossibleCharactersEnd    
    SET @index = PATINDEX(@searchString, @ResultString)
    WHILE @index > 0
    BEGIN
        SET @NResultString = STUFF(@NResultString, @index + 1, LEN(@BrandName), @BrandNameNew)
        SET @ResultString = @NResultString

        SET @index = PATINDEX(@searchString, @ResultString)
    END

    --The brand name at the END
    SET @searchString = N'' + @PossibleCharactersBegin + @BrandName 
    SET @index = PATINDEX(@searchString, @ResultString)
    WHILE @index > 0
    BEGIN
        SET @NResultString = STUFF(@NResultString, @index + 1, LEN(@BrandName), @BrandNameNew)
        SET @ResultString = @NResultString

        SET @index = PATINDEX(@searchString, @ResultString)
    END

    RETURN @NResultString
END

我使用了备用变量来保持输入字符串的 NVARCHAR 格式,并在其 VARCHAR 等效项上使用 patindex,并且工作正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-02
    • 2017-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-12
    相关资源
    最近更新 更多