Вопрос по parsing, sql-server – Как убрать все не алфавитные символы из строки в SQL Server?

151

Как вы можете удалить из строки все символы, которые не являются буквенными?

А как насчет не алфавитно-цифровых?

Должна ли это быть пользовательская функция или существуют более обобщенные решения?

Эта ссылка может помочь вам ....codefari.com/2014/10/remove-special-characters-from-string.html Singh

Ваш Ответ

18   ответов
330

Create Function [dbo].[RemoveNonAlphaCharacters](@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^a-z]%'
    While PatIndex(@KeepValues, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    Return @Temp
End

Назовите это так:

Select dbo.RemoveNonAlphaCharacters('abc1234def5678ghi90jkl')

Как только вы поймете код, вы увидите, что его относительно просто изменить, чтобы удалить другие символы. Вы даже можете сделать это достаточно динамичным, чтобы передать ваш шаблон поиска.

Надеюсь, поможет.

Этот код удаляет не-буквенные символы (поэтому числа также удаляются). Если вы хотите оставить цифры (удалить не буквенно-цифровые символы), то ... замените ^ a-z на ^ a-z ^ 0-9. Эта строка поиска появляется в коде в двух разных местах. Обязательно замените их обоих.
@Lynchie Change & apos;% [^ a-z]% & amp; До «% [^ a-z]%» В основном, просто поставьте пробел после z.
Из комментария Джеффа: Я думаю, что если бы вы хотели убрать все не буквы и не цифры, вы бы хотели & quot; ^ a-z0-9 & ap; (по сравнению с '^ a-z ^ 0-9', который оставил бы ^ в строке). Even Mien
+1 Джордж. Это одно из тех мест, где «на основе набора» код и использование встроенных скалярных функций имеют большие трудности при разбивании строк по строкам. Красиво сделано. Я также использовал ваши "Начальные буквы" функция, которая имеет ту же основную форму, в течение пары лет, сейчас.
Имя переменной KeepValues фактически противоположно тому, для чего она предназначена. KeepValues перечисляет символы, которые должны быть исключены ..
-1

Проблема, с которой я столкнулся при решении выше, состоит в том, что он не отфильтровывает такие символы, как & # xE7 ;, & # xEB ;, & # xEF; и т. Д. Я адаптировал функцию следующим образом (для экономии памяти я использовал только строку 80 varchar) :

create FUNCTION dbo.udf_Cleanchars (@InputString varchar(80)) 
RETURNS varchar(80) 
AS 

BEGIN 
declare @return varchar(80) , @length int , @counter int , @cur_char char(1) 
SET @return = '' 
SET @length = 0 
SET @counter = 1 
SET @length = LEN(@InputString) 
IF @length > 0 
BEGIN WHILE @counter <= @length 

BEGIN SET @cur_char = SUBSTRING(@InputString, @counter, 1) IF ((ascii(@cur_char) in (32,44,46)) or (ascii(@cur_char) between 48 and 57) or (ascii(@cur_char) between 65 and 90) or (ascii(@cur_char) between 97 and 122))
BEGIN SET @return = @return + @cur_char END 
SET @counter = @counter + 1 
END END 

RETURN @return END
Я думаю, что вы должны перейти по этой ссылкеcodefari.com/2014/10/remove-special-characters-from-string.html
Спасибо тебе за это, Эрик. Как вы говорите, ответ с пометкой «очень хорошо», но он не лишает глупости «числовой» ответ. такие символы, как & # xBD ;.
2

Numbers таблица целых чисел (которая должна быть у вас под рукой, если вы хотите выполнять серьезные операции с запросами с хорошей производительностью). Не требует CTE. Вы можете изменитьNOT IN (...) выражение, чтобы исключить определенные символы, или изменить его наIN (...) ИЛИ ЖЕLIKE выражение, чтобы сохранить только определенные символы.

SELECT (
    SELECT  SUBSTRING([YourString], N, 1)
    FROM    dbo.Numbers
    WHERE   N > 0 AND N <= CONVERT(INT, LEN([YourString]))
        AND SUBSTRING([YourString], N, 1) NOT IN ('(',')',',','.')
    FOR XML PATH('')
) AS [YourStringTransformed]
FROM ...
Интересное решение не связанной проблемы.
3

iTVF, Во-первых, вам нужен сплиттер на основе шаблона. Вот один, взятый из лагеря Дуэйнаarticle:

-- PatternSplitCM will split a string based on a pattern of the form 
-- supported by LIKE and PATINDEX 
-- 
-- Created by: Chris Morris 12-Oct-2012 
CREATE FUNCTION [dbo].[PatternSplitCM]
(
       @List                VARCHAR(8000) = NULL
       ,@Pattern            VARCHAR(50)
) RETURNS TABLE WITH SCHEMABINDING 
AS 

RETURN
    WITH numbers AS (
        SELECT TOP(ISNULL(DATALENGTH(@List), 0))
            n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
        FROM
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n)
    )

    SELECT
        ItemNumber = ROW_NUMBER() OVER(ORDER BY MIN(n)),
        Item = SUBSTRING(@List,MIN(n),1+MAX(n)-MIN(n)),
        [Matched]
    FROM (
        SELECT n, y.[Matched], Grouper = n - ROW_NUMBER() OVER(ORDER BY y.[Matched],n)
        FROM numbers
        CROSS APPLY (
            SELECT [Matched] = CASE WHEN SUBSTRING(@List,n,1) LIKE @Pattern THEN 1 ELSE 0 END
        ) y
    ) d
    GROUP BY [Matched], Grouper

Теперь, когда у вас есть сплиттер на основе шаблона, вам нужно разделить строки, соответствующие шаблону:

[a-z]

и затем объединить их обратно, чтобы получить желаемый результат:

SELECT *
FROM tbl t
CROSS APPLY(
    SELECT Item + ''
    FROM dbo.PatternSplitCM(t.str, '[a-z]')
    WHERE Matched = 1
    ORDER BY ItemNumber
    FOR XML PATH('')
) x (a)

SAMPLE

Результат:

| Id |              str |              a |
|----|------------------|----------------|
|  1 |    test“te d'abc |     testtedabc |
|  2 |            anr¤a |           anra |
|  3 |  gs-re-C“te d'ab |     gsreCtedab |
|  4 |         M‚fe, DF |          MfeDF |
|  5 |           R™temd |          Rtemd |
|  6 |          ™jad”ji |          jadji |
|  7 |      Cje y ret¢n |       Cjeyretn |
|  8 |        J™kl™balu |        Jklbalu |
|  9 |       le“ne-iokd |       leneiokd |
| 10 |   liode-Pyr‚n‚ie |    liodePyrnie |
| 11 |         V„s G”ta |          VsGta |
| 12 |        Sƒo Paulo |        SoPaulo |
| 13 |  vAstra gAtaland | vAstragAtaland |
| 14 |  ¥uble / Bio-Bio |     ubleBioBio |
| 15 | U“pl™n/ds VAsb-y |    UplndsVAsby |
есть ли преимущество, чтобы использовать это перед другими ответами?
0
DECLARE @vchVAlue NVARCHAR(255) = 'SWP, Lettering Position 1: 4 Ω, 2: 8 Ω, 3: 16 Ω, 4:  , 5:  , 6:  , Voltage Selector, Solder, 6, Step switch, : w/o fuseholder '


WHILE PATINDEX('%?%' , CAST(@vchVAlue AS VARCHAR(255))) > 0
  BEGIN
    SELECT @vchVAlue = STUFF(@vchVAlue,PATINDEX('%?%' , CAST(@vchVAlue AS VARCHAR(255))),1,' ')
  END 

SELECT @vchVAlue
1

PatIndex('%[^A-Za-z0-9]%', @Temp)

для пользовательской функции выше RemoveNonAlphaCharacters и переименовал ее RemoveNonAlphaNumericCharacters

-3

что это встроено в Oracle 10g, если это то, что вы используете. Мне пришлось убрать все специальные символы для сравнения номера телефона.

regexp_replace(c.phone, '[^0-9]', '')
& quot; SQL Server & quot; относится конкретно к продукту Microsoft.
4

в моей системе эта уродливая функция работает лучше, чем элегантная G Mastros.

CREATE FUNCTION dbo.RemoveSpecialChar (@s VARCHAR(256)) 
RETURNS VARCHAR(256) 
WITH SCHEMABINDING
    BEGIN
        IF @s IS NULL
            RETURN NULL
        DECLARE @s2 VARCHAR(256) = '',
                @l INT = LEN(@s),
                @p INT = 1

        WHILE @p <= @l
            BEGIN
                DECLARE @c INT
                SET @c = ASCII(SUBSTRING(@s, @p, 1))
                IF @c BETWEEN 48 AND 57
                   OR  @c BETWEEN 65 AND 90
                   OR  @c BETWEEN 97 AND 122
                    SET @s2 = @s2 + CHAR(@c)
                SET @p = @p + 1
            END

        IF LEN(@s2) = 0
            RETURN NULL

        RETURN @s2
как насчет общих запятых, точек, пробелов и т. д.?
насколько отличается, если вы не используетеASCII целое число здесь и сравнить непосредственно выводSUBSTRING с некоторыми символами, например:SET @ch=SUBSTRING(@s, @p, 1) а такжеIF @ch BETWEEN '0' AND '9' OR @ch BETWEEN 'a' AND 'z' OR @ch BETWEEN 'A' AND 'Z' ...
0

ла, затем FOR XML для согласования со строкой сохраненных значений, которые вы можете ...

CREATE FUNCTION [dbo].[PatRemove](
    @pattern varchar(50),
    @expression varchar(8000) 
    )
RETURNS varchar(8000)
AS
BEGIN
    WITH 
        d(d) AS (SELECT d FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) digits(d)),
        nums(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM d d1, d d2, d d3, d d4),
        chars(c) AS (SELECT SUBSTRING(@expression, n, 1) FROM nums WHERE n <= LEN(@expression))
    SELECT 
        @expression = (SELECT c AS [text()] FROM chars WHERE c NOT LIKE @pattern FOR XML PATH(''));

    RETURN @expression;
END
1

- Сначала создайте одну функцию

CREATE FUNCTION [dbo].(@strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
     DECLARE @intAlpha INT
     SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric)
BEGIN
     WHILE @intAlpha > 0
   BEGIN
          SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
          SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric )
   END
END
RETURN ISNULL(@strAlphaNumeric,0)
END

Теперь вызовите эту функцию как

select [dbo].('Abhi12shek23jaiswal')

Его результат как

1223
144

G Mastros& APOS;потрясающий ответ:

CREATE FUNCTION [dbo].[fn_StripCharacters]
(
    @String NVARCHAR(MAX), 
    @MatchExpression VARCHAR(255)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    SET @MatchExpression =  '%['[email protected]+']%'

    WHILE PatIndex(@MatchExpression, @String) > 0
        SET @String = Stuff(@String, PatIndex(@MatchExpression, @String), 1, '')

    RETURN @String

END

Только в алфавитном порядке:

SELECT dbo.fn_StripCharacters('[email protected]#f4$', '^a-z')

Только числовые:

SELECT dbo.fn_StripCharacters('[email protected]#f4$', '^0-9')

Только буквенно-цифровой:

SELECT dbo.fn_StripCharacters('[email protected]#f4$', '^a-z0-9')

Не буквенно-цифровые:

SELECT dbo.fn_StripCharacters('[email protected]#f4$', 'a-z0-9')
Шаблон регулярного выражения, кажется, не работает со всеми пробелами. Если я хочу удалить все специальные символы, кроме буквенно-цифровых символов и пробелов, которые я ожидаю использоватьSELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9\s') который все еще лишает пробелов. Я также пытался использовать[[:blank:]] но это нарушает функцию и ничего не удаляется из строки. Ближайший Ive получил с помощью:SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9 ') (жесткое кодирование пробела в шаблоне регулярных выражений). Однако это не удаляет разрывы строк.
Я предпочитаю эту версию и создал свою адаптацию G Mastros & apos; ответьте, прежде чем прокрутить вниз, чтобы проголосовать!
@BillyMcKee Добавьте пробел в начале, а не в конце регулярного выражения.SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^ a-z0-9')
4

что SQL плохо работает со строками, но я не думал, что это будет так сложно. Вот простая функция, чтобы вырезать все числа из строки. Были бы лучшие способы сделать это, но это только начало.

CREATE FUNCTION dbo.AlphaOnly (
    @String varchar(100)
)
RETURNS varchar(100)
AS BEGIN
  RETURN (
    REPLACE(
      REPLACE(
        REPLACE(
          REPLACE(
            REPLACE(
              REPLACE(
                REPLACE(
                  REPLACE(
                    REPLACE(
                      REPLACE(
                        @String,
                      '9', ''),
                    '8', ''),
                  '7', ''),
                '6', ''),
              '5', ''),
            '4', ''),
          '3', ''),
        '2', ''),
      '1', ''),
    '0', '')
  )
END
GO

-- ==================
DECLARE @t TABLE (
    ColID       int,
    ColString   varchar(50)
)

INSERT INTO @t VALUES (1, 'abc1234567890')

SELECT ColID, ColString, dbo.AlphaOnly(ColString)
FROM @t

Output

ColID ColString
----- ------------- ---
    1 abc1234567890 abc

Round 2 - Data-Driven Blacklist

-- ============================================
-- Create a table of blacklist characters
-- ============================================
IF EXISTS (SELECT * FROM sys.tables WHERE [object_id] = OBJECT_ID('dbo.CharacterBlacklist'))
  DROP TABLE dbo.CharacterBlacklist
GO
CREATE TABLE dbo.CharacterBlacklist (
    CharID              int         IDENTITY,
    DisallowedCharacter nchar(1)    NOT NULL
)
GO
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'0')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'1')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'2')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'3')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'4')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'5')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'6')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'7')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'8')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'9')
GO

-- ====================================
IF EXISTS (SELECT * FROM sys.objects WHERE [object_id] = OBJECT_ID('dbo.StripBlacklistCharacters'))
  DROP FUNCTION dbo.StripBlacklistCharacters
GO
CREATE FUNCTION dbo.StripBlacklistCharacters (
    @String nvarchar(100)
)
RETURNS varchar(100)
AS BEGIN
  DECLARE @blacklistCt  int
  DECLARE @ct           int
  DECLARE @c            nchar(1)

  SELECT @blacklistCt = COUNT(*) FROM dbo.CharacterBlacklist

  SET @ct = 0
  WHILE @ct < @blacklistCt BEGIN
    SET @ct = @ct + 1

    SELECT @String = REPLACE(@String, DisallowedCharacter, N'')
    FROM dbo.CharacterBlacklist
    WHERE CharID = @ct
  END

  RETURN (@String)
END
GO

-- ====================================
DECLARE @s  nvarchar(24)
SET @s = N'abc1234def5678ghi90jkl'

SELECT
    @s                  AS OriginalString,
    dbo.StripBlacklistCharacters(@s)   AS ResultString

Output

OriginalString           ResultString
------------------------ ------------
abc1234def5678ghi90jkl   abcdefghijkl

My challenge to readers: Can you make this more efficient? What about using recursion?

вы могли бы написать лучший dbo.StripBlacklistCharacters () без использования циклаsommarskog.se/arrays-in-sql-2005.html#tblnum table of numbers joined into your black list table, but I'm too lazy today to try it myself.... – KM. Jun 17 '09 at 19:59
0

так как я пытался сохранить арабские буквы, которые я пытался заменить регулярным выражением, но также он не работал. я написал другой метод для работы на уровне ASCII, так как это был мой единственный выбор, и он работал.

 Create function [dbo].[RemoveNonAlphaCharacters] (@s varchar(4000)) returns varchar(4000)
   with schemabinding
begin
   if @s is null
      return null
   declare @s2 varchar(4000)
   set @s2 = ''
   declare @l int
   set @l = len(@s)
   declare @p int
   set @p = 1
   while @p <= @l begin
      declare @c int
      set @c = ascii(substring(@s, @p, 1))
      if @c between 48 and 57 or @c between 65 and 90 or @c between 97 and 122 or @c between 165 and 253 or @c between 32 and 33
         set @s2 = @s2 + char(@c)
      set @p = @p + 1
      end
   if len(@s2) = 0
      return null
   return @s2
   end

ИДТИ

4

чтобы просто добавить функции к вашим производственным данным, но вы все еще хотите выполнить этот вид фильтрации, то это чистое решение SQL, использующее таблицу PIVOT для повторного объединения отфильтрованных частей.

N.B. Я жестко закодировал таблицу длиной до 40 символов, вам придется добавить больше, если у вас есть более длинные строки для фильтрации.

SET CONCAT_NULL_YIELDS_NULL OFF;

with 
    ToBeScrubbed
as (
    select 1 as id, '*SOME [email protected] [email protected]* #* BOGUS [email protected]*&! DATA' as ColumnToScrub
),

Scrubbed as (
    select 
        P.Number as ValueOrder,
        isnull ( substring ( t.ColumnToScrub , number , 1 ) , '' ) as ScrubbedValue,
        t.id
    from
        ToBeScrubbed t
        left join master..spt_values P
            on P.number between 1 and len(t.ColumnToScrub)
            and type ='P'
    where
        PatIndex('%[^a-z]%', substring(t.ColumnToScrub,P.number,1) ) = 0
)

SELECT
    id, 
    [1]+ [2]+ [3]+ [4]+ [5]+ [6]+ [7]+ [8] +[9] +[10]
    +  [11]+ [12]+ [13]+ [14]+ [15]+ [16]+ [17]+ [18] +[19] +[20]
    +  [21]+ [22]+ [23]+ [24]+ [25]+ [26]+ [27]+ [28] +[29] +[30]
    +  [31]+ [32]+ [33]+ [34]+ [35]+ [36]+ [37]+ [38] +[39] +[40] as ScrubbedData
FROM (
    select 
        *
    from 
        Scrubbed
    ) 
    src
    PIVOT (
        MAX(ScrubbedValue) FOR ValueOrder IN (
        [1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
        [11], [12], [13], [14], [15], [16], [17], [18], [19], [20],
        [21], [22], [23], [24], [25], [26], [27], [28], [29], [30],
        [31], [32], [33], [34], [35], [36], [37], [38], [39], [40]
        )
    ) pvt
Для меня это решение было в 2,3 раза быстрее, чем использование функции для набора из 235 тыс. Строк. Я также должен был сделать 2 замены, и использовал в общей сложности четыре CTE. Работал как чемпион.
2

которые вам не нужны. Проблема в том, что вам нужно указать, какие символы вам не нужны. Если в вас войдет новый персонаж, он пройдет, если вы не добавите его в список.

Положительным моментом является то, что вам не нужно создавать специальную функцию. У меня нет прав на запись, так что это позволяет мне выполнять простой запрос.

REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
p.Name
,'®','')
,'©','')
,'ö','o')
,'ë','e')
,'ä','a')
,'ü','u')
,'ú','u')
,'í','i')
,'ï','i')
,'™','')
,'é','e')
,'²','2')
,'è','e')
,'—','-')
,'–','-')
,'ó','o')
,'•',' ')
,'…','.')
,'ô','o')
,'â','a')
,'á','a')
,'ê','e')
,'è','e')
,'’',' ')
,'·',' ')
,'à','a')
,'å','a')
,'ã','a')
,'’',' ')
,'a€s','as')
,'ø','o')
,'ñ','n')
,'î','i')
,'ç','c')
,'Ç','C')
,'Ã','A')
,'”','"')
,'“','"')
,'Á','A')
,'¢','c')
,'Ã','A')
,'Å','A')
,'¶','S')
,'×','x')
,'†','')
,'š','')
,'¤','')
,'µ','')
,'õ','')
,'€','')
,'‘','')
,'Õ','')
,'ð','')
,'Ò','')
,'¨','')
,'º','')
,'°','')
,'ì','')
,'ƒ','')
,'ÿ','')
,'ß','')
,'«','')
,'»','')
,'Æ','')
,'¬','')
,'Ù','')
,'ý','')
,'û','')
,'|','')
    as Name
1

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[udf_RemoveNumericCharsFromString]
(
@List NVARCHAR(4000)
)
RETURNS TABLE 
AS RETURN

    WITH GetNums AS (
       SELECT TOP(ISNULL(DATALENGTH(@List), 0))
        n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
        FROM
          (VALUES (0),(0),(0),(0)) d (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n)
            )

    SELECT StrOut = ''+
        (SELECT Chr
         FROM GetNums
            CROSS APPLY (SELECT SUBSTRING(@List , n,1)) X(Chr)
         WHERE Chr LIKE '%[^0-9]%' 
         ORDER BY N
         FOR XML PATH (''),TYPE).value('.','NVARCHAR(MAX)')


   /*How to Use
   SELECT StrOut FROM dbo.udf_RemoveNumericCharsFromString ('vv45--9gut')
   Result: vv--gut
   */
Я знаю, что этот поток старый, но встроенная табличная функция - это путь. Проблема с вашим решением состоит в том, что вы 'только возвращаете числа, этот код:), TYPE) .value (".", "NVARCHAR (MAX)") не требуется и замедлит работу на ~ 50%
4

я подумал, что должен существовать метод чистого SQL, который не требует функции или запроса CTE / XML и не требует сложного обслуживания вложенных операторов REPLACE. Вот мое решение:

SELECT 
  x
  ,CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 1, 1) + '%' THEN '' ELSE SUBSTRING(x, 1, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 2, 1) + '%' THEN '' ELSE SUBSTRING(x, 2, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 3, 1) + '%' THEN '' ELSE SUBSTRING(x, 3, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 4, 1) + '%' THEN '' ELSE SUBSTRING(x, 4, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 5, 1) + '%' THEN '' ELSE SUBSTRING(x, 5, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 6, 1) + '%' THEN '' ELSE SUBSTRING(x, 6, 1) END
-- Keep adding rows until you reach the column size 
    AS stripped_column
FROM (SELECT 
        column_to_strip AS x
        ,'ABCDEFGHIJKLMNOPQRSTUVWXYZ' AS a 
      FROM my_table) a

Преимущество такого способа состоит в том, что в подстроке содержатся допустимые символы, что упрощает перенастройку для другого набора символов.

Недостатком является то, что вам нужно добавить строку SQL для каждого символа вплоть до размера вашего столбца. Чтобы упростить эту задачу, я просто использовал приведенный ниже скрипт Powershell, например, для VARCHAR (64):

1..64 | % {
  "    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, {0}, 1) + '%' THEN '' ELSE SUBSTRING(x, {0}, 1) END" -f $_
} | clip.exe
Неудобно в общем случае, но легко и полезно для разового запроса с узким столбцом.
2

которое не требует создания функции или перечисления всех экземпляров символов для замены. Он использует рекурсивный оператор WITH в сочетании с PATINDEX для поиска нежелательных символов. Он заменит все нежелательные символы в столбце - до 100 уникальных плохих символов, содержащихся в любой заданной строке. (Например, «ABC123DEF234» будет содержать 4 неправильных символа 1, 2, 3 и 4). Ограничение 100 - это максимальное количество рекурсий, допустимое в операторе WITH, но это не накладывает ограничения на число строк, которые нужно обработать, который ограничен только доступной памятью.
Если вам не нужны результаты DISTINCT, вы можете удалить две опции из кода.

-- Create some test data:
SELECT * INTO #testData 
FROM (VALUES ('ABC DEF,K.l(p)'),('123H,J,234'),('ABCD EFG')) as t(TXT)

-- Actual query:
-- Remove non-alpha chars: '%[^A-Z]%'
-- Remove non-alphanumeric chars: '%[^A-Z0-9]%'
DECLARE @BadCharacterPattern VARCHAR(250) = '%[^A-Z]%';

WITH recurMain as (
    SELECT DISTINCT CAST(TXT AS VARCHAR(250)) AS TXT, PATINDEX(@BadCharacterPattern, TXT) AS BadCharIndex
    FROM #testData
    UNION ALL
    SELECT CAST(TXT AS VARCHAR(250)) AS TXT, PATINDEX(@BadCharacterPattern, TXT) AS BadCharIndex
    FROM (
        SELECT 
            CASE WHEN BadCharIndex > 0 
                THEN REPLACE(TXT, SUBSTRING(TXT, BadCharIndex, 1), '')
                ELSE TXT 
            END AS TXT
        FROM recurMain
        WHERE BadCharIndex > 0
    ) badCharFinder
)
SELECT DISTINCT TXT
FROM recurMain
WHERE BadCharIndex = 0;

Похожие вопросы