空白(スペース、タブ、改行)を削除する


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スカラーUDFまたはT-SQLインラインTVF(iTVF)として作成できます。T-SQLインライン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~

そしてあなたはそれをUPDATEusingで使うことができます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

冒頭で述べたように、.NETにはTrim()必要な操作を正確に実行するメソッドが含まれているため、これはSQLCLRを介しても非常に簡単です。独自に呼び出してを呼び出す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の出力例とまったく同じ文字列を返します。ただし、スカラーUDFであるため、次のように使用しますUPDATE

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

上記のいずれも、数百万行にわたって使用する場合に効率的です。インラインTVFは、マルチステートメントTVFやT-SQLスカラーUDFとは異なり、最適化できます。また、SQLCLRスカラーUDFは、IsDeterministic=trueどちらのタイプのDataAccessにも設定されておらずRead(ユーザーとシステムの両方のデータアクセスのデフォルトがNone)、これらの条件が両方とも設定されている限り、並列プランで使用される可能性があります。上記の両方のSQLCLR関数に対してtrueです。


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ステートメントで使用できます。

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 )文字のリストを受け入れる関数は、トリミングします多くのスクリプト言語が持っているように。
Giovanni Lovato 2016年

「おそらく」多くの行でうまく機能しないことについて私が出した警告は、問題である場合とそうでない場合があります。これを1回だけ行う場合は、問題にはならない可能性があります。実稼働環境以外でテストして、所要時間を確認することができます。
Max Vernon

答えを更新して、updateステートメントでこれをどのように使用するかを示します。
Max Vernon

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 2017

はい、あなたは正しいです、私は編集します
sami.almasagedi

-1

LTRIM / RTRIMはスペースのみをトリムするため、2番目の例を解析する必要があります。SQLがデータと見なすもの(/ r、/ tなど)を実際にトリムしたい場合。探している値がわかっている場合は、REPLACEを使用して置き換えてください。さらに良いのは、関数を記述して呼び出すことです。


-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
スカラー値関数はほとんどエレガントではありません。クエリを強制的に順次実行し、行ごとに1回(クエリごとに1回ではなく)実行します。代わりにインラインテーブル値関数を見てください。
エリックダーリン

-2

大きなデータに対して関数を使用すると、実行時間が長くなる可能性があります。800万行のデータセットがあり、usingfunctionの実行に30分以上かかりました。replace(replace(replace(replace(@COLUMN,CHAR(9),''),CHAR(10),''),CHAR(13),''),CHAR(32),'')わずか5秒かかりました。皆さんありがとう。@ sami.almasagediと@Colin 't Hart


あなたが繰り返している答えのように、これは最初と最後の非空白文字の間の空白を保持する必要がある場合、問題を解決しません。速度は、望ましい答えが得られる場合にのみ役立ちます。また、関数がこのようなクエリの速度を落とさないようにする方法について、承認された回答のメモを参照してください。
RDFozz 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.