ฟังก์ชัน LEN ไม่รวมช่องว่างต่อท้ายใน SQL Server


109

ฉันมีตารางทดสอบต่อไปนี้ใน SQL Server 2005:

CREATE TABLE [dbo].[TestTable]
(
 [ID] [int] NOT NULL,
 [TestField] [varchar](100) NOT NULL
) 

เติมด้วย:

INSERT INTO TestTable (ID, TestField) VALUES (1, 'A value');   -- Len = 7
INSERT INTO TestTable (ID, TestField) VALUES (2, 'Another value      '); -- Len = 13 + 6 spaces

เมื่อฉันพยายามค้นหาความยาวของ TestField ด้วยฟังก์ชัน SQL Server LEN () จะไม่นับช่องว่างต่อท้าย - เช่น:

-- Note: Also results the grid view of TestField do not show trailing spaces (SQL Server 2005).
SELECT 
 ID, 
 TestField, 
 LEN(TestField) As LenOfTestField, -- Does not include trailing spaces
FROM 
 TestTable

ฉันจะรวมช่องว่างต่อท้ายในผลลัพธ์ความยาวได้อย่างไร


1
ฉันคิดว่าทางออกที่แท้จริงที่นี่อาจมีไว้สำหรับ Microsoft เพื่อแก้ไขซอฟต์แวร์ที่เสีย โหวตที่นี่: feedback.azure.com/forums/908035-sql-server/suggestions/…
QA Collective

คำตอบ:


125

เอกสารนี้เป็นเอกสารอย่างชัดเจนโดย Microsoft ใน MSDN ที่http://msdn.microsoft.com/en-us/library/ms190329(SQL.90).aspxซึ่งระบุว่า LEN "ส่งคืนจำนวนอักขระของนิพจน์สตริงที่ระบุโดยไม่รวม ช่องว่างต่อท้าย ". อย่างไรก็ตามเป็นรายละเอียดที่ง่ายที่จะพลาดหากคุณไม่ระวัง

คุณต้องใช้ฟังก์ชัน DATALENGTH แทน - โปรดดูที่http://msdn.microsoft.com/en-us/library/ms173486(SQL.90).aspx - ซึ่ง "ส่งกลับจำนวนไบต์ที่ใช้แทนนิพจน์ใด ๆ "

ตัวอย่าง:

SELECT 
    ID, 
    TestField, 
    LEN(TestField) As LenOfTestField,           -- Does not include trailing spaces
    DATALENGTH(TestField) As DataLengthOfTestField      -- Shows the true length of data, including trailing spaces.
FROM 
    TestTable

52
หมายเหตุ: สำหรับDATALENGTHคุณยังจะต้องแบ่งผล 2 ถ้าการแสดงออกที่ถูกทดสอบเป็นชนิดตัวกว้าง (Unicode; nchar, nvarchar หรือ ntext) เนื่องจากผลที่ได้คือในไบต์ไม่ได้ตัวละคร
devstuff

7
นอกจากนี้สำหรับvarcharอื่น ๆ สิ่งนี้อาจขึ้นอยู่กับการเรียงและแม้แต่การหารตรงไปข้างหน้าด้วย 2 ก็เชื่อถือได้ ดูตัวอย่างที่นี่
Martin Smith

18
ฉันจะใช้LEN(REPLACE(expr, ' ', '_')). สิ่งนี้ควรใช้ได้กับvarcharและnvarcharและสตริงที่มีอักขระควบคุมยูนิโคดพิเศษ
Olivier Jacot-Descombes

6
-1 DATALENGTH()ไม่ควรได้รับการพิจารณาทางเลือกในการนับตัวละครเพราะมันนับไบต์แทนของตัวละครและเรื่องนี้เมื่อเป็นตัวแทนของสายเดียวกันใน/VARCHAR NVARCHAR
binki

5
เริ่มจาก SQL Server 2012 คอลัมน์ Unicode ที่มีการเปรียบเทียบเวอร์ชัน 100 รองรับคู่ตัวแทนแล้ว ซึ่งหมายความว่าอักขระเดี่ยวอาจใช้ได้ถึง 4 ไบต์ทำให้การหารด้วยสองเคล็ดลับล้มเหลว ดูMSDN
Frédéric

85

คุณสามารถใช้เคล็ดลับนี้:

เลน (Str + 'x') - 1


15
คุณช่วยสอนเราเกี่ยวกับทางเลือกที่ดีกว่าได้ไหม? Datalength ไม่แน่ใจ
เสิร์จ

15
ฉันไม่เห็นด้วยอย่างยิ่งว่าการใช้วิธีที่ไม่สอดคล้องกัน (ในบางกรณีคุณหารผลลัพธ์ด้วย 2 แต่บางครั้งก็ไม่ได้) เป็นตัวเลือกที่ดีกว่า อาจจะมีประสิทธิภาพที่ใกล้ถึงศูนย์ด้วยวิธีการของฉัน
เสิร์จ

5
วิธีการของ @usr Serge ดีที่สุด IMHO เรียบง่ายและสง่างาม DATALENGTH มีความซับซ้อน: ขึ้นอยู่กับประเภทไบต์เดี่ยว / คู่, การเรียง / ขึ้นอยู่กับภาษา ฯลฯ
Mr. TA

10
นี่เป็นทางออกที่ดีที่สุดและสวยงาม ฉันไม่สนใจจริงๆว่ามันจะรู้สึกเหมือนแฮ็คหรือไม่ (การเข้ารหัสไม่เกี่ยวกับความรู้สึก) ฉันสนใจจริงๆว่าโซลูชันนี้ไม่มีผลข้างเคียง ฉันสามารถเปลี่ยนชนิดข้อมูล varchar / nvarchar ได้และยังใช้งานได้ ทำได้ดีมาก
Mike Keskinov

5
มีข้อแม้เพราะผลข้างเคียงนี้ หากคุณกำลังทำงานกับตัวแปรประเภท nvarchar (4000) และตัวแปรของคุณมีสตริงอักขระ 4000 อักขระที่เพิ่มจะถูกละเว้นและคุณจะได้ผลลัพธ์ที่ไม่ถูกต้อง (len ของ SQL ที่ละเว้นช่องว่างต่อท้ายน้อยกว่า 1 คุณลบ)
ขวาน - ทำด้วย SOverflow

17

ฉันใช้วิธีนี้:

LEN(REPLACE(TestField, ' ', '.'))

ฉันชอบสิ่งนี้มากกว่า DATALENGTH เพราะใช้งานได้กับประเภทข้อมูลที่แตกต่างกันและฉันชอบมากกว่าการเพิ่มอักขระต่อท้ายเพราะคุณไม่ต้องกังวลกับขอบกรณีที่สตริงของคุณมีความยาวสูงสุดอยู่แล้ว

หมายเหตุ: ฉันจะทดสอบประสิทธิภาพก่อนที่จะใช้กับชุดข้อมูลขนาดใหญ่มาก แม้ว่าฉันจะทดสอบกับ 2M แถวและก็ไม่ช้าไปกว่า LEN ที่ไม่มี REPLACE ...


14

"ฉันจะรวมช่องว่างต่อท้ายในผลลัพธ์ความยาวได้อย่างไร"

คุณได้รับใครบางคนเพื่อยื่นคำร้องขอการปรับปรุงเซิร์ฟเวอร์ SQL / รายงานข้อบกพร่องเนื่องจากเกือบทั้งหมดที่ระบุไว้สำหรับปัญหาง่ายๆที่น่าอัศจรรย์นี้ที่นี่มีข้อบกพร่องบางอย่างหรือไม่มีประสิทธิภาพ สิ่งนี้ยังดูเหมือนจะเป็นจริงใน SQL Server 2012 คุณลักษณะการตัดแต่งอัตโนมัติอาจมาจาก ANSI / ISO SQL-92 แต่ดูเหมือนว่าจะมีบางช่องโหว่ (หรือไม่มีการนับ)

โปรดลงคะแนน "เพิ่มการตั้งค่าเพื่อให้ LEN นับช่องว่างต่อท้าย" ที่นี่:

https://feedback.azure.com/forums/908035-sql-server/suggestions/34673914-add-setting-so-len-counts-trailing-whitespace

ลิงค์ Retired Connect: https://connect.microsoft.com/SQLServer/feedback/details/801381


2
การdatalengthแก้ปัญหานั้นแย่ลงกว่าเดิมโดยเริ่มจาก SQL server 2012 เนื่องจากตอนนี้รองรับคู่ตัวแทนใน UTF-16 ซึ่งหมายความว่าอักขระอาจใช้ได้ถึง 4 ไบต์ ถึงเวลาแล้วที่พวกเขาแก้ไขlenฟังก์ชันเพื่อให้สอดคล้องกับ ANSI หรืออย่างน้อยก็มีฟังก์ชันเฉพาะสำหรับการนับอักขระรวมถึงช่องว่างต่อท้าย
Frédéric

1
ลิงก์คำติชมจำเป็นต้องใช้มากขึ้นสำหรับสิ่งนี้ เป็นเรื่องน่างงที่ปัญหานี้สามารถค้นหาได้ทางอินเทอร์เน็ตเท่านั้น ฉันใช้เวลาเกือบ 2 ชั่วโมงในการพยายามหาว่าฉันทำผิดพลาดในรหัสของตัวเองก่อนที่จะพิจารณาว่าฟังก์ชัน LEN () เป็นสาเหตุของการตัดการเชื่อมต่อของฉัน
Takophiliac

ฉันเห็นด้วยกับสิ่งนี้ แต่ควรอนุญาตให้พารามิเตอร์ตัดช่องว่างออก .. เนื่องจากทำให้การเปรียบเทียบสตริงกับ EF ง่ายขึ้นมากโดยไม่ต้องตรวจสอบว่ามีช่องว่างรวมอยู่หรือไม่เมื่อสร้างนิพจน์ที่ถามได้
ganjeii

9

มีปัญหากับสองคำตอบที่ได้รับการโหวตสูงสุด คำตอบที่แนะนำDATALENGTHมีแนวโน้มที่จะเกิดข้อผิดพลาดของโปรแกรมเมอร์ ผลลัพธ์ของDATALENGTHต้องหารด้วย 2 สำหรับNVARCHARประเภท แต่ไม่ใช่สำหรับVARCHARประเภท DATALENGTHเรื่องนี้ต้องมีความรู้เกี่ยวกับประเภทที่คุณจะได้รับความยาวของและถ้าว่าการเปลี่ยนแปลงชนิดที่คุณต้องขยันขันแข็งเปลี่ยนสถานที่ที่คุณใช้

นอกจากนี้ยังมีปัญหากับคำตอบที่ได้รับการโหวตมากที่สุด (ซึ่งฉันยอมรับว่าเป็นวิธีที่ฉันชอบที่จะทำจนกว่าปัญหานี้จะกัดฉัน) หากสิ่งที่คุณจะได้รับความยาวของเป็นชนิดNVARCHAR(4000)และเป็นจริงมีสตริง 4000 อักขระ SQL NVARCHAR(MAX)จะไม่สนใจตัวอักษรต่อท้ายมากกว่าโดยปริยายโยนผลให้ ผลลัพธ์สุดท้ายคือความยาวไม่ถูกต้อง สิ่งเดียวกันนี้จะเกิดขึ้นกับ VARCHAR (8000)

สิ่งที่ฉันพบทำงานได้เกือบจะเร็วเท่าแบบเก่าLENเร็วกว่าLEN(@s + 'x') - 1สตริงขนาดใหญ่และไม่ถือว่าความกว้างของอักขระที่อยู่ภายใต้ดังต่อไปนี้:

DATALENGTH(@s) / DATALENGTH(LEFT(LEFT(@s, 1) + 'x', 1))

สิ่งนี้ได้รับความยาวคลื่นจากนั้นหารด้วยความยาวคลื่นของอักขระเดี่ยวจากสตริง การต่อท้ายของ 'x' ครอบคลุมกรณีที่สตริงว่างเปล่า (ซึ่งจะให้หารด้วยศูนย์ในกรณีนั้น) งานนี้ไม่ว่าจะ@sเป็นหรือVARCHAR NVARCHARการทำLEFTอักขระ 1 ตัวก่อนที่จะต่อท้ายบางครั้งเมื่อสตริงมีขนาดใหญ่ แม้ว่าปัญหานี้คือมันทำงานไม่ถูกต้องกับสตริงที่มีคู่ตัวแทน

REPLACE(@s,' ','x')มีวิธีอื่นที่กล่าวถึงในความคิดเห็นที่ตอบรับการใช้เป็น เทคนิคนั้นให้คำตอบที่ถูกต้อง แต่คำสั่งขนาดสองสามคำสั่งช้ากว่าเทคนิคอื่น ๆ เมื่อสตริงมีขนาดใหญ่

จากปัญหาที่คู่ตัวแทนแนะนำเกี่ยวกับเทคนิคใด ๆ ที่ใช้DATALENGTHฉันคิดว่าวิธีที่ปลอดภัยที่สุดที่ให้คำตอบที่ถูกต้องที่ฉันรู้มีดังต่อไปนี้:

LEN(CONVERT(NVARCHAR(MAX), @s) + 'x') - 1

เร็วกว่าREPLACEเทคนิคนี้และเร็วกว่ามากด้วยสตริงที่ยาวกว่า โดยพื้นฐานแล้วเทคนิคนี้เป็นLEN(@s + 'x') - 1เทคนิค แต่มีการป้องกันกรณีขอบที่สตริงมีความยาว 4000 (สำหรับ nvarchar) หรือ 8000 (สำหรับ varchar) เพื่อให้ได้คำตอบที่ถูกต้องแม้กระทั่งสำหรับสิ่งนั้น นอกจากนี้ควรจัดการกับสตริงที่มีคู่ตัวแทนอย่างถูกต้อง


1
น่าเสียดายที่คำตอบนี้ใช้ไม่ได้กับสตริงที่มีคู่ตัวแทนใน SQL Server 2012 อีกต่อไปการรันการดำเนินการของคุณในการN'x𤭢x' COLLATE Latin1_General_100_CI_AS_SCให้ 4 ในขณะที่LENให้ 3.
Douglas

9
@ ดักลาส - นั่นเป็นข้อมูลที่มีประโยชน์ หากมีเพียง Microsoft เท่านั้นที่จะให้ LEN เวอร์ชันที่ไม่สนใจช่องว่างต่อท้าย
ขวาน - ทำด้วย SOverflow

5

คุณต้องแน่ใจด้วยว่าข้อมูลของคุณได้รับการบันทึกจริงด้วยช่องว่างต่อท้าย เมื่อANSI PADDINGปิดอยู่ (ไม่ใช่ค่าเริ่มต้น):

ช่องว่างต่อท้ายในค่าอักขระที่แทรกในคอลัมน์ varchar จะถูกตัดออก


3
ฉันคิดว่าคุณไม่ควรปิด ANSI PADDING เนื่องจากการตั้งค่านี้ล้าสมัย การมีค่าที่ไม่ได้มาตรฐานทำให้เกิดปัญหาเล็กน้อยมากมาย
usr

4

LEN จะตัดช่องว่างต่อท้ายตามค่าเริ่มต้นดังนั้นฉันจึงพบว่าสิ่งนี้ใช้ได้ผลเมื่อคุณย้ายไปด้านหน้า

(เลน (ย้อนกลับ (สนามทดสอบ))

ดังนั้นหากคุณต้องการคุณสามารถพูดได้

SELECT
t.TestField,
LEN(REVERSE(t.TestField)) AS [Reverse],
LEN(t.TestField) AS [Count]
FROM TestTable t
WHERE LEN(REVERSE(t.TestField)) <> LEN(t.TestField)

อย่าใช้สิ่งนี้สำหรับช่องว่างชั้นนำแน่นอน


9
ตอนนี้มันจดจ้องช่องว่างนำหน้าแทนที่จะเป็นช่องว่างต่อท้าย วันเดียวกันปัญหาต่างกัน :)
Reversed Engineer

@DaveBoltman ข้อเสนอแนะของฉันน่าจะยังคงซับซ้อนกว่านี้ แต่คุณสามารถเปรียบเทียบกับความยาวของ TRIM'ed ได้
Brian J

สิ่งนี้จะกลับจุดบกพร่องโดยที่ไม่นับช่องว่างนำหน้าแทนที่จะเป็นช่องว่างต่อท้าย ดูรหัสต่อไปนี้ declare @TestField varchar(10); SET @TestField = ' abc '; -- Length with spaces is 5. select LEN(REVERSE(@TestField)) -- Returns 4 select LEN(@TestField) -- Returns 4
Metalogic

1

คุณควรกำหนดฟังก์ชัน CLR ที่ส่งคืนฟิลด์ความยาวของสตริงหากคุณไม่ชอบการต่อสายอักขระ ฉันใช้LEN('x' + @string + 'x') - 2ในกรณีการใช้งานการผลิตของฉัน


0

หากคุณไม่ชอบDATALENGTHเนื่องจากข้อกังวลเกี่ยวกับ n / varchar ให้ทำอย่างไร:

select DATALENGTH(@var)/isnull(nullif(DATALENGTH(left(@var,1)),0),1)

ซึ่งเป็นเพียง

select DATALENGTH(@var)/DATALENGTH(left(@var,1))

ห่อด้วยการป้องกันแบบหารด้วยศูนย์

การหารด้วย DATALENGTH ของอักขระเดี่ยวเราจะได้ความยาวที่เป็นมาตรฐาน

(แน่นอนว่ายังคงมีปัญหากับคู่ตัวแทนหากเป็นปัญหา)


-4

ใช้ SELECT DATALENGTH ('string')


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