web-dev-qa-db-fra.com

Couper les espaces (espaces, tabulations, sauts de ligne)

Je suis sur SQL Server 2014 et je dois nettoyer les espaces blancs du début et de la fin du contenu d'une colonne, où les espaces blancs peuvent être de simples espaces, des tabulations ou des retours à la ligne (les deux \n et \r\n); par exemple.

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

etc.

Je n'ai pu réaliser que le premier cas avec

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

mais pour les autres cas cela ne fonctionne pas.

10
Giovanni Lovato

Pour toute personne utilisant SQL Server 2017 ou plus récent

vous pouvez utiliser la fonction intégrée TRIM . Par exemple:

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'~';

Veuillez noter que le comportement par défaut de TRIM est de supprimer uniquement les espaces, donc pour supprimer également les tabulations et les sauts de ligne (CR + LF), vous devez spécifier la clause characters FROM.

De plus, j'ai utilisé NCHAR(0x09) pour les caractères de tabulation dans la variable @Test Afin que l'exemple de code puisse être copié-collé et conserver les caractères corrects. Sinon, les tabulations sont converties en espaces lors du rendu de cette page.

Pour toute personne utilisant SQL Server 2016 ou une version antérieure

Vous pouvez créer une fonction, soit en tant qu'UDF scalaire SQLCLR, soit en tant que TVF T-SQL Inline (iTVF). La TVF T-SQL Inline serait la suivante:

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

Et l'exécuter comme suit:

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;

Retour:

proof
----
~this 
              content~

Et vous pouvez l'utiliser dans un UPDATE en utilisant 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

Comme mentionné au début, cela est également très facile via SQLCLR car .NET inclut une méthode Trim() qui effectue exactement l'opération souhaitée. Vous pouvez soit coder la vôtre pour appeler SqlString.Value.Trim(), soit installer simplement la version gratuite de la bibliothèque SQL # (que j'ai créée, mais cette fonction est dans la version gratuite) et utilisez soit String_Trim (qui ne fait que des espaces blancs) ou String_TrimChars où vous passez les caractères à couper des deux côtés (tout comme l'iTVF illustré ci-dessus).

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];

Et il renvoie exactement la même chaîne que celle montrée ci-dessus dans l'exemple de sortie iTVF. Mais étant un UDF scalaire, vous l'utiliseriez comme suit dans un UPDATE:

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

L'une ou l'autre des solutions ci-dessus doit être efficace pour une utilisation sur des millions de lignes. Les TVF en ligne sont optimisables contrairement aux TVF à instructions multiples et aux FDU scalaires T-SQL. De plus, les FDU scalaires SQLCLR peuvent être utilisés dans des plans parallèles, tant qu'ils sont marqués comme IsDeterministic=true Et ne définissent aucun type de DataAccess sur Read (valeur par défaut pour les utilisateurs et les utilisateurs). L'accès aux données système est None), et ces deux conditions sont vraies pour les deux fonctions SQLCLR mentionnées ci-dessus.

8
Solomon Rutzky

Vous voudrez peut-être envisager d'utiliser une TVF (fonction de valeur de table) pour supprimer les caractères incriminés du début et de la fin de vos données.

Créez une table pour stocker les données de test:

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

Créez le 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

Exécutez le TVF pour afficher les résultats:

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

Résultats:

enter image description here

Le TVF s'appelle récursivement jusqu'à ce qu'il ne reste aucun caractère incriminé au début et à la fin de la chaîne passée dans la fonction. Il est peu probable que cela fonctionne bien sur un grand nombre de lignes, mais cela fonctionnerait probablement bien si vous utilisez cela pour corriger les données lors de leur insertion dans la base de données.

Vous pouvez l'utiliser dans une déclaration de mise à jour:

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


SELECT *
FROM dbo.TrimTest;

Résultats (sous forme de texte):

enter image description here

4
Max Vernon

J'ai juste eu un problème avec cette situation particulière, j'avais besoin de trouver et de nettoyer chaque champ avec des espaces blancs, mais j'ai trouvé 4 types d'espaces blancs possibles dans mes champs de base de données (Référence à ASCII table de code ):

  • Onglet horizontal (caractère (9))
  • Nouvelle ligne (char (10))
  • Onglet vertical (char (9))
  • Espace (char (32))

Peut-être que cette requête peut vous aider.

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