Заменить специальные символы в столбце пробелом


10

Я пытаюсь написать запрос, который заменяет специальные символы пробелом. Код ниже помогает идентифицировать строки. (допустимы буквенно-цифровые символы, запятая и пробел):

SELECT columnA
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

Как интегрировать функцию замены в оператор выбора, чтобы все символы, кроме буквенно-цифровых, запятой и пробела в наборе результатов, заменялись на '' (пробел). Этот не будет работать:

SELECT replace(columnA,'%[^a-Z0-9, ]%',' ')
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

Ответы:


11

Если вы гарантированно когда-либо будете использовать только 26 букв английского алфавита США (как в верхнем, так и в нижнем регистре), тогда, конечно, вы можете избежать использования LIKEи / или PATINDEXс помощью простого обозначения диапазона [a-z](вы не станете необходимо использовать прописные буквы "Z" при использовании сортировки без учета регистра).

Но, если вы можете получить символы , которые не нашли в ан-США алфавит еще доступны в различных кодовых страниц / Collations для VARCHARданных (например , Þ= Latin капитал «Торн» = 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

Теперь, если вы поддерживаете NVARCHARданные и можете получать символы «слова» из разных языков, тогда T-SQL не поможет, поскольку у него нет реального способа дифференцировать эти вещи. В этом случае вам следует использовать Регулярное выражение (RegEx) - в частности, Replaceметод / функцию - и они доступны только через SQLCLR. Ниже приведен пример замены нескольких «специальных» символов, но при этом все действительные буквы оставлены как минимум на одном языке:

DECLARE @Test NVARCHAR(500);
SET @Test = N'this$is%a<>TEST,;to}⌡↕strip╞╟╚══¶out_ç_ƒ▀ special-ij-೫-chars-舛-დ-א-B';
SELECT SQL#.RegEx_Replace4k(@Test, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL); 

Возвращает:

this is a  TEST, to   strip      out ç ƒ  special ij ೫ chars 舛 დ א B

Выражение RegEx означает:

  • \W= А RegEx «побег» , что означает «любой нон -Word характер»
  • \p{Pc}= Unicode "категория" из "Пунктуации, Соединитель" (это необходимо только для соответствия, потому что эта "категория" специально исключена \Wescape)
  • -[,]= вычитание класса (это необходимо для исключения запятых из соответствия как «особенных», так как они включены в \Wescape)

Вы можете обновить таблицу, просто выполнив:

UPDATE tbl
SET    tbl.field = SQL#.RegEx_Replace4k(tbl.field, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL)
FROM   tbl
WHERE  SQL#.RegEx_IsMatch4k(tbl.field, N'[\W\p{Pc}-[,]]', 1, NULL) = 1;

Обратите внимание, что для этих примеров я использовал две функции, доступные в библиотеке SQL # версии Free # функций SQLCLR, которые я создал (но, опять же, они бесплатны). Также обратите внимание, что я использовал версии «4k», которые быстрее благодаря использованию NVARCHAR(4000)вместо NVARCHAR(MAX)типов параметров. Если ваши данные используются NVARCHAR(MAX), то просто удалите «4k» из имен функций.

Пожалуйста, смотрите также:


5

У меня здесь есть пост, который делает что-то подобное .

В основном я использую рекурсивный 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);

Вы должны быть в состоянии изменить нижнюю часть, чтобы сделать обновление, а не просто запрос, но я на самом деле не пробовал. Я уверен, что это будет выглядеть примерно так:

UPDATE FixBadChars
SET StringToFix = FixedString
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

Что касается масштабируемости, я вернул ~ 170 тыс. Очищенных строк менее чем за 30 секунд. Опять же, не уверен насчет обновления, но это было на моем ноутбуке, который довольно медленный с только 6 ГБ оперативной памяти.


0
Declare @String nchar(2000)='hg$%^AB,.:23ab-=+'

Declare @NewString VARCHAR(2000)=''
Declare @Lenght int=LEN(@String)
Declare @Index int=1

WHILE (@Index <= @Lenght)
BEGIN
    Declare @Letter nchar(1)=Substring(@String,@Index,1);
    Declare @ASCII int=ASCII(@Letter);
    If((@ASCII >= 48 and @ASCII <= 57) or (@ASCII >= 97 and @ASCII <= 122) or (@ASCII >= 65 and @ASCII <= 90))
    BEGIN
        SET @NewString += @Letter
    END
    ELSE
    BEGIN
        SET @NewString += ' '
    END
    SET @Index+=1

END
Select @NewString
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.