Boşluğu kırp (boşluklar, sekmeler, yeni satırlar)


10

Ben SQL Server 2014 ve ben boşluk basit boşluk, sekme veya yeni satırlar (her ikisi olabilecek bir sütunun içeriği, başlangıcı ve bitişi temiz boşluk gerekir \nve \r\n); Örneğin

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

ve bunun gibi.

Sadece ilk davayı

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

ancak diğer durumlarda işe yaramaz.

Yanıtlar:


8

SQL Server 2017 veya daha yenisini kullanan herkes için

Kullanabileceğiniz TRIM yerleşik işlevi. Örneğin:

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

Varsayılan davranışının TRIMyalnızca boşlukları kaldırmak olduğunu unutmayın , bu nedenle sekmeleri ve yeni satırları da (CR + LF) kaldırmak için characters FROMyan tümceyi belirtmeniz gerekir .

Ayrıca, örnek kodun kopyalanıp yapıştırılabilmesi ve doğru karakterlerin korunabilmesi NCHAR(0x09)için @Testdeğişkende sekme karakterleri için kullandım . Aksi takdirde, bu sayfa oluşturulduğunda sekmeler boşluklara dönüştürülür.

SQL Server 2016 veya daha eski sürüm kullanan herkes için

SQLCLR Skaler UDF veya T-SQL Inline TVF (iTVF) olarak bir işlev oluşturabilirsiniz. T-SQL Inline TVF aşağıdaki gibi olacaktır:

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

Ve aşağıdaki gibi çalıştırın:

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;

İadeler:

proof
----
~this 
              content~

Ve bir odasını kullanabilirler UPDATEkullanarak 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

Başlangıçta belirtildiği gibi, SQLCLR aracılığıyla bu gerçekten kolaydır, çünkü .NET Trim()tam olarak istediğiniz işlemi yapan bir yöntem içerir . Ya kod kendi çağırmak olabilir SqlString.Value.Trim(), ya da sadece serbest sürümünü yükleyebilirsiniz SQL # kütüphanesinden (benim yarattığım, ancak bu fonksiyon Ücretsiz sürümünde) ve kullanım ya String_Trim (sadece boşluk yapar) veya String_TrimChars nerede her iki taraftan da kırpmak için karakterleri geçirirsiniz (tıpkı yukarıda gösterilen iTVF gibi).

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

Ve yukarıda iTVF örnek çıktısında gösterilenle aynı dizeyi döndürür. Ancak skaler bir UDF olarak, bunu aşağıdaki gibi kullanırsınız UPDATE:

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

Yukarıdakilerden biri milyonlarca sıra boyunca kullanmak için verimli olmalıdır. Satır içi TVF'ler, Multi-ifadeli TVF'lerin ve T-SQL skaler UDF'lerin aksine optimize edilebilir. Ve SQLCLR Skaler UDF'ler, IsDeterministic=trueher iki tür DataAccess'i Read(hem Kullanıcı hem de Sistem veri erişimi için varsayılan değer) olarak ayarladıkları sürece paralel planlarda kullanılma potansiyeline sahiptir Noneve bu koşulların her ikisi de yukarıda belirtilen her iki SQLCLR fonksiyonu için de geçerlidir.


4

Sorun yaratan karakterleri verilerinizin başından ve sonundan kaldırmak için TVF (tablo değerli işlev) kullanmayı düşünebilirsiniz.

Test verilerini tutmak için bir tablo oluşturun:

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'yi oluşturun:

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

Sonuçları göstermek için TVF'yi çalıştırın:

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

Sonuçlar:

resim açıklamasını buraya girin

TVF, işleve iletilen dizenin başında ve sonunda hiçbir rahatsız edici karakter kalmayana kadar kendini yinelemeli olarak çağırır. Bu, çok sayıda satır üzerinde iyi performans gösterme olasılığı düşüktür, ancak veritabanına eklenirken verileri düzeltmek için bunu kullanıyorsanız, muhtemelen iyi çalışır.

Bunu bir güncelleme ifadesinde kullanabilirsiniz:

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


SELECT *
FROM dbo.TrimTest;

Sonuçlar (metin olarak):

resim açıklamasını buraya girin


Teşekkür ederim Max, ne yazık ki birden çok tablodaki çok sayıda satır (milyon) temizlemeliyim, / UPDATEgibi bir sorguda kullanılmak üzere bazı işlevlerde , satırlarda bir şey kırpmak için bir karakter listesi kabul eden bir işlevle umut birçok komut dosyası dili gibi. LTRIMRTRIMUPDATE table t SET t.column = TRIM(t.column, CONCAT(CHAR(9), CHAR(10), CHAR(13)))TRIM( expression, charlist )
Giovanni Lovato

Bu konuda verdiğim uyarı "muhtemelen" çok sayıda satır üzerinde iyi çalışmıyor sorun olabilir veya olmayabilir. Bunu sadece bir kez yapıyorsanız, sorun olmayabilir. Üretim dışı bir ortamda test etmek isteyebilirsiniz, böylece ne kadar sürdüğünü görebilirsiniz.
Max Vernon

Bunu bir updateifadede nasıl kullanacağınızı göstermek için cevabımı güncelleyeceğim .
Max Vernon

1

Ben sadece bu özel durum ile ilgili bir sorun vardı, ben bulmak ve beyaz boşluk ile her alanı temizlemek için gerekli, ama veritabanı alanları (ASCII kod tablosuna Referans) 4 boşluk beyaz boşluk bulundu:

  • Yatay Sekme (karakter (9))
  • New Line (karakter (10))
  • Dikey Sekme (karakter (9))
  • Uzay (Char (32))

Belki bu sorgu size yardımcı olabilir.

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

Bu, boşlukları alanların ortasından da temizler, yalnızca soruda sorulduğu gibi başlangıç ​​ve bitiş değil.
Colin 't Hart

Evet, haklısın, düzenleyeceğim
sami.almasagedi

-1

LTRIM / RTRIM yalnızca boşlukları kırptığı için ikinci örneği ayrıştırmanız gerekir. Aslında SQL'in veri (/ r, / t, vb.) Aradığınız değerleri biliyorsanız, değiştirmek için REPLACE kullanın. Daha da iyisi, bir işlev yazın ve çağırın.


-1

İsterseniz zarif fonksiyonumu kullan:

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
Skaler değerli fonksiyonlar neredeyse zarif değildir. Sorguları seri olarak çalışmaya ve satır başına bir kez (sorgu başına bir kez değil) yürütmeye zorlarlar. Bunun yerine satır içi tablo değerli işlevlere bakmalısınız.
Erik Darling

-2

Fonksiyonu büyük verilerde kullanmak uzun sürebilir. 8 milyon satırlık bir veri kümem var, kullanma işlevinin yürütülmesi 30 dakikadan fazla sürdü. replace(replace(replace(replace(@COLUMN,CHAR(9),''),CHAR(10),''),CHAR(13),''),CHAR(32),'')sadece 5 saniye sürdü. Hepinize teşekkürler. @ Sami.almasagedi ve @Colin 't Hart'ı görüyorum


Tekrarladığınız cevapta olduğu gibi, ilk ve son boşluk olmayan karakterler arasındaki boşluk korunmak zorundaysa, bu sorunu çözmez. Hız sadece istenen cevabı verdiğinde kullanışlıdır. Ayrıca - işlevlerin böyle bir sorguyu yavaşlatmamasını sağlamak için kabul edilen yanıttaki notlara bakın.
RDFozz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.