Обріжте пробіли (пробіли, вкладки, нові рядки)


10

Я на SQL Server 2014 і мені потрібно очистити пробіли від початку та до кінця вмісту стовпця, де пробіли можуть бути простими пробілами, вкладками чи новими рядками (і \nта \r\n); напр

'    this content    '                          should become 'this content'
'  \r\n   \t\t\t this \r\n content \t  \r\n   ' should become 'this \r\n content'

і так далі.

Мені вдалося досягти лише першого випадку

UPDATE table t SET t.column = LTRIM(RTRIM(t.column))

але для інших випадків це не працює.

Відповіді:


8

Для всіх, хто використовує SQL Server 2017 або новіших версій

ви можете використовувати вбудовану функцію TRIM . Наприклад:

DECLARE @Test NVARCHAR(4000);
SET @Test = N'  
    ' + NCHAR(0x09) + N'  ' + NCHAR(0x09) + N' this 
 ' + NCHAR(0x09) + NCHAR(0x09) + N'  content' + NCHAR(0x09) + NCHAR(0x09) + N'  
' + NCHAR(0x09) + N' ' + NCHAR(0x09) + NCHAR(0x09) + N'     ';

SELECT N'~'
        + TRIM(NCHAR(0x09) + NCHAR(0x20) + NCHAR(0x0D) + NCHAR(0x0A) FROM @Test)
        + N'~';

Зауважте, що за замовчуванням поведінка - TRIMце видалення лише пробілів, тому для того, щоб також видаляти вкладки та нові рядки (CR + LF), вам потрібно вказати characters FROMпункт.

Також я використовував NCHAR(0x09)для символів вкладки @Testзмінної, щоб примірний код можна було скопіювати та вставити та зберегти правильні символи. В іншому випадку вкладки перетворюються на пробіли, коли ця сторінка надається.

Для всіх, хто використовує SQL Server 2016 або новіші

Ви можете створити функцію або як SQLCLR Scalar UDF, або T-SQL Inline TVF (iTVF). TF-SQL Inline TVF буде таким:

CREATE
--ALTER
FUNCTION dbo.TrimChars(@OriginalString NVARCHAR(4000), @CharsToTrim NVARCHAR(50))
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN
WITH cte AS
(
  SELECT PATINDEX(N'%[^' + @CharsToTrim + N']%', @OriginalString) AS [FirstChar],
         PATINDEX(N'%[^' + @CharsToTrim + N']%', REVERSE(@OriginalString)) AS [LastChar],
        LEN(@OriginalString + N'~') - 1 AS [ActualLength]
)
SELECT cte.[ActualLength],
       [FirstChar],
       ((cte.[ActualLength] - [LastChar]) + 1) AS [LastChar],
       SUBSTRING(@OriginalString, [FirstChar],
                 ((cte.[ActualLength] - [LastChar]) - [FirstChar] + 2)) AS [FixedString]
FROM   cte;
GO

І виконується так:

DECLARE @Test NVARCHAR(4000);
SET @Test = N'  
    ' + NCHAR(0x09) + N'  ' + NCHAR(0x09) + N' this 
 ' + NCHAR(0x09) + NCHAR(0x09) + N'  content' + NCHAR(0x09) + NCHAR(0x09) + N'  
' + NCHAR(0x09) + N' ' + NCHAR(0x09) + NCHAR(0x09) + N'     ';

SELECT N'~' + tc.[FixedString] + N'~' AS [proof]
FROM   dbo.TrimChars(@Test, NCHAR(0x09) + NCHAR(0x20) + NCHAR(0x0D) + NCHAR(0x0A)) tc;

Повернення:

proof
----
~this 
              content~

І ви можете використовувати це у UPDATEвикористанні CROSS APPLY:

UPDATE tbl
SET    tbl.[Column] = itvf.[FixedString]
FROM   SchemaName.TableName tbl
CROSS APPLY  dbo.TrimChars(tbl.[Column],
                           NCHAR(0x09) + NCHAR(0x20) + NCHAR(0x0D) + NCHAR(0x0A)) itvf

Як було сказано на початку, це також дуже просто через SQLCLR, оскільки .NET включає Trim()метод, який робить саме ту операцію, яку ви хочете. Ви можете або кодувати свій власний дзвінок SqlString.Value.Trim(), або ви можете просто встановити безкоштовну версію бібліотеки SQL # (яку я створив, але ця функція є у вільній версії) та використовувати або String_Trim (що робить просто пробіл), або String_TrimChars, де ви передаєте символи для обрізки з обох сторін (подібно до iTVF, показаного вище).

DECLARE @Test NVARCHAR(4000);
SET @Test = N'  
    ' + NCHAR(0x09) + N'  ' + NCHAR(0x09) + N' this 
 ' + NCHAR(0x09) + NCHAR(0x09) + N'  content' + NCHAR(0x09) + NCHAR(0x09) + N'  
' + NCHAR(0x09) + N' ' + NCHAR(0x09) + NCHAR(0x09) + N'     ';

SELECT N'~' + SQL#.String_Trim(@Test) + N'~' AS [proof];

І він повертає точно такий же рядок, як показано вище у висновку iTVF. Але будучи скалярною АДС, ви використовуєте її в наступному UPDATE:

UPDATE tbl
SET    tbl.[Column] = SQL#.String_Trim(itvf.[Column])
FROM   SchemaName.TableName tbl

Будь-яке з перерахованих вище має бути ефективним для використання у мільйонах рядків. Вбудовані телевізійні канали оптимізуються на відміну від ТВФ з кількома заявами та скалярними UDF T-SQL. І, скалярні UDF SQLCLR можуть використовуватись у паралельних планах, якщо вони позначені як IsDeterministic=trueі не встановлюють жодного типу DataAccess Read(за замовчуванням для доступу користувачів та системних даних None), і обидва ці умови є справедливо для обох зазначених вище функцій SQLCLR.


4

Можливо, ви захочете скористатись TVF (функцією, що розрахована на таблицю) для видалення символів, які порушують вас, з початку та в кінці даних.

Створіть таблицю для зберігання даних тесту:

IF COALESCE(OBJECT_ID('dbo.TrimTest'), 0) <> 0
BEGIN
    DROP TABLE dbo.TrimTest;
END
CREATE TABLE dbo.TrimTest
(
    SampleData VARCHAR(50) NOT NULL
);

INSERT INTO dbo.TrimTest (SampleData)
SELECT CHAR(13) + CHAR(10) + CHAR(9) + 'this is ' + CHAR(13) + CHAR(10) + ' a test' + CHAR(13) + CHAR(10);
GO

Створіть TVF:

IF COALESCE(OBJECT_ID('dbo.StripCrLfTab'), 0) <> 0
BEGIN
    DROP FUNCTION dbo.StripCrLfTab;
END
GO
CREATE FUNCTION dbo.StripCrLfTab
(
    @val NVARCHAR(1000)
)
RETURNS @Results TABLE
(
    TrimmedVal NVARCHAR(1000) NULL
)
AS
BEGIN
    DECLARE @TrimmedVal NVARCHAR(1000);
    SET @TrimmedVal = CASE WHEN RIGHT(@val, 1) = CHAR(13) OR RIGHT(@val, 1) = CHAR(10) OR RIGHT(@val, 1) = CHAR(9)
            THEN LEFT(
                CASE WHEN LEFT(@val, 1) = CHAR(13) OR LEFT(@val, 1) = CHAR(10) OR LEFT(@val, 1) = CHAR(9)
                THEN RIGHT(@val, LEN(@val) - 1)
                ELSE @val
                END
                , LEN(@val) -1 )
            ELSE
                CASE WHEN LEFT(@val, 1) = CHAR(13) OR LEFT(@val, 1) = CHAR(10) OR LEFT(@val, 1) = CHAR(9)
                THEN RIGHT(@val, LEN(@val) - 1)
                ELSE @val
                END
            END;
    IF @TrimmedVal LIKE (CHAR(13) + '%')
        OR @TrimmedVal LIKE (CHAR(10) + '%')
        OR @TrimmedVal LIKE (CHAR(9) + '%')
        OR @TrimmedVal LIKE ('%' + CHAR(13))
        OR @TrimmedVal LIKE ('%' + CHAR(10))
        OR @TrimmedVal LIKE ('%' + CHAR(9))
        SELECT @TrimmedVal = tv.TrimmedVal
        FROM dbo.StripCrLfTab(@TrimmedVal) tv;
    INSERT INTO @Results (TrimmedVal)
    VALUES (@TrimmedVal);
    RETURN;
END;
GO

Запустіть TVF, щоб показати результати:

SELECT tt.SampleData
    , stt.TrimmedVal
FROM dbo.TrimTest tt
CROSS APPLY dbo.StripCrLfTab(tt.SampleData) stt;

Результати:

введіть тут опис зображення

TVF викликує себе рекурсивно, поки на початку та в кінці рядка не передаються функції, які залишилися порушуючими символами. Це навряд чи буде працювати над великою кількістю рядків, але, ймовірно, спрацює нормально, якщо ви використовуєте це для виправлення даних, оскільки вони вставляються в базу даних.

Ви можете використовувати це в операторі оновлення:

UPDATE dbo.TrimTest
SET TrimTest.SampleData = stt.TrimmedVal
FROM dbo.TrimTest tt
CROSS APPLY dbo.StripCrLfTab(tt.SampleData) stt;


SELECT *
FROM dbo.TrimTest;

Результати (у тексті):

введіть тут опис зображення


Дякую Макс, на жаль, мені доведеться очистити велику кількість рядків (мільйонів) у кількох таблицях, я сподівався, що якусь функцію використовуватимуть у UPDATEзапиті, як LTRIM/ RTRIM, щось у рядках UPDATE table t SET t.column = TRIM(t.column, CONCAT(CHAR(9), CHAR(10), CHAR(13)))із TRIM( expression, charlist )функцією, яка приймає список символів для обрізки як у багатьох мов сценаріїв.
Джованні Ловато

Попередження, яке я дав про це, "ймовірно", що воно не працює надто багато рядків, може бути або не бути проблемою. Якщо ви робите це лише один раз, то це може не бути проблемою. Можливо, ви захочете перевірити його у невиробничому середовищі, щоб ви могли побачити, як довго це займає.
Макс Вернон

Я оновлю свою відповідь, щоб показати, як ви це використовуєте у updateзаяві.
Макс Вернон

1

У мене просто була проблема з цією конкретною ситуацією, мені потрібно було знайти та очистити кожне поле з пробілами, але я знайшов 4 типи можливих пробілів у моїх полях баз даних (Посилання на кодову таблицю ASCII):

  • Горизонтальна вкладка (char (9))
  • Нова лінія (char (10))
  • Вертикальна вкладка (char (9))
  • Космос (char (32))

Можливо, цей запит може вам допомогти.

UPDATE @TABLE SET @COLUMN = replace(replace(replace(replace(@COLUMN,CHAR(9),''),CHAR(10),''),CHAR(13),''),CHAR(32),'')

Це також очищає пробіли від середини полів, а не лише початок і кінець, як задано в питанні.
Colin 't Hart

Так, ви маєте рацію, я редагую
sami.almasagedi

-1

Вам потрібно буде проаналізувати другий приклад, оскільки LTRIM / RTRIM обробляє лише пробіли. Ви насправді хочете вирішити те, що SQL вважає даними (/ r, / t тощо). Якщо ви знаєте шукані значення, просто замініть їх заміною. А ще краще - написати функцію та зателефонувати їй.


-1

Якщо вам подобається, використовуйте мою елегантну функцію:

CREATE FUNCTION s_Trim
(
    @s nvarchar(max)
)
RETURNS nvarchar(max)
AS
BEGIN
    -- Create comparators for LIKE operator
    DECLARE @whitespaces nvarchar(50) = CONCAT('[ ', CHAR(9), CHAR(10), CHAR(13), ']'); -- Concat chars that you consider as whitespaces
    DECLARE @leftComparator nvarchar(50) = @whitespaces + '%',
            @rightComparator nvarchar(50) = '%' + @whitespaces;
    -- LTRIM
    WHILE @s LIKE @leftComparator AND LEN(@s + 'x') > 1 SET @s = RIGHT(@s, LEN(@s + 'x') - 2)
    -- RTRIM
    WHILE @s LIKE @rightComparator AND LEN(@s + 'x') > 1 SET @s = LEFT(@s, LEN(@s + 'x') - 2)

    RETURN @s;
END
GO

1
Функції, що оцінюються за шкалою, навряд чи елегантні. Вони змушують запити виконуватись послідовно та виконувати один раз у рядку (не один раз за запитом). Ви повинні замість цього переглянути функції вбудованої таблиці з цінністю.
Ерік Дарлінг

-2

Використання функції на великих даних може зайняти тривалий час виконання. У мене є набір даних у 8 мільйонів рядків, для використання функції знадобилося більше 30 хвилин. replace(replace(replace(replace(@COLUMN,CHAR(9),''),CHAR(10),''),CHAR(13),''),CHAR(32),'')зайняли лише 5 сек. Дякую всім. Я бачу вас @ sami.almasagedi та @Colin 't Hart


Як і у відповіді, яку ви повторюєте, це не вирішує проблему, якщо пробіл між першим і останнім символами непробільного простору повинен бути збережений. Швидкість корисна лише тоді, коли вона спричинить бажану відповідь. Також - див. Примітки до прийнятої відповіді про те, як переконатися, що функції не сповільнюють такий запит.
RDFozz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.