ตัดช่องว่าง (ช่องว่างแท็บบรรทัดใหม่)


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 + LFs) คุณต้องระบุcharacters FROMข้อ

นอกจากนี้ฉันใช้NCHAR(0x09)สำหรับอักขระแท็บใน@Testตัวแปรเพื่อให้สามารถคัดลอกและวางโค้ดตัวอย่างและเก็บอักขระที่ถูกต้องได้ มิฉะนั้นแท็บจะถูกแปลงเป็นช่องว่างเมื่อมีการแสดงผลหน้านี้

สำหรับทุกคนที่ใช้ SQL Server 2016 ขึ้นไป

คุณสามารถสร้างฟังก์ชั่นไม่ว่าจะเป็น SQLCLR Scalar UDF หรือ T-SQL Inline TVF (iTVF) T-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 แต่เป็น UDF สเกลาร์คุณจะใช้มันดังต่อไปนี้ในUPDATE:

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

อย่างใดอย่างหนึ่งข้างต้นควรมีประสิทธิภาพสำหรับการใช้ข้ามแถวนับล้าน TVFs แบบอินไลน์สามารถปรับให้เหมาะสมได้ซึ่งแตกต่างจากคำสั่ง TVFs แบบหลายคำสั่งและ UDF แบบ scalar T-SQL และ SQLCLR Scalar UDFs มีศักยภาพที่จะใช้ในแผนคู่ขนานตราบใดที่มีการทำเครื่องหมายเป็น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 )ฟังก์ชั่นที่ยอมรับรายการอักขระเพื่อตัดแต่ง เหมือนภาษาสคริปต์มากมาย
Giovanni Lovato

คำเตือนที่ฉันให้ไว้เกี่ยวกับเรื่องนี้ "อาจจะ" ทำงานได้ไม่ดีในหลายแถวอาจจะใช่หรือไม่ใช่ปัญหาก็ได้ หากคุณกำลังทำสิ่งนี้เพียงครั้งเดียวอาจไม่เป็นปัญหา คุณอาจต้องการทดสอบในสภาพแวดล้อมที่ไม่ใช่การผลิตเพื่อให้คุณสามารถดูว่าใช้เวลานานเท่าใด
Max Vernon

ฉันจะอัปเดตคำตอบของฉันเพื่อแสดงว่าคุณจะใช้สิ่งนี้อย่างไรในupdateแถลงการณ์
Max Vernon

1

ฉันเพิ่งมีปัญหากับสถานการณ์นี้ฉันต้องการค้นหาและทำความสะอาดทุกช่องที่มีช่องว่างสีขาว แต่ฉันพบช่องว่างสีขาว 4 ประเภทในช่องฐานข้อมูลของฉัน (อ้างอิงจากตารางรหัส ASCII):

  • แถบแนวนอน (ถ่าน (9))
  • บรรทัดใหม่ (อักขระ (10))
  • แท็บแนวตั้ง (อักขระ (9))
  • พื้นที่ (ถ่าน (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
ฟังก์ชั่นที่มีคุณค่าของเกลานั้นแทบจะไม่หรูหรา พวกมันบังคับให้คิวรีเรียกใช้แบบอนุกรมและดำเนินการหนึ่งครั้งต่อแถว (ไม่ใช่หนึ่งครั้งต่อแบบสอบถาม) คุณควรดูฟังก์ชั่นที่มีค่าของตารางแบบอินไลน์แทน
Erik Darling

-2

การใช้ฟังก์ชั่นกับข้อมูลขนาดใหญ่อาจใช้เวลาดำเนินการนาน ฉันมีชุดข้อมูล 8 ล้านแถวการใช้ฟังก์ชั่นใช้เวลามากกว่า 30 นาทีในการดำเนินการ replace(replace(replace(replace(@COLUMN,CHAR(9),''),CHAR(10),''),CHAR(13),''),CHAR(32),'')ใช้เวลาเพียง 5 วินาที ขอบคุณทุกคน ฉันเห็นคุณ @ sami.almasagedi และ @Colin 't Hart


ในคำตอบที่คุณทำซ้ำสิ่งนี้จะไม่แก้ปัญหาหากช่องว่างระหว่างอักขระที่ไม่ใช่ช่องว่างตัวแรกและตัวสุดท้ายต้องคงไว้ ความเร็วจะมีประโยชน์ก็ต่อเมื่อได้ผลลัพธ์ตามที่ต้องการเท่านั้น นอกจากนี้ - ดูบันทึกย่อในคำตอบที่ได้รับการยอมรับเกี่ยวกับวิธีการทำให้แน่ใจว่าฟังก์ชั่นจะไม่ทำให้แบบสอบถามช้าลง
RDFozz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.