Hàm LEN không bao gồm dấu cách ở cuối trong SQL Server


109

Tôi có bảng kiểm tra sau trong SQL Server 2005:

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

Được phổ biến với:

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

Khi tôi cố gắng tìm độ dài của TestField bằng hàm LEN () của SQL Server, nó không tính khoảng cách ở cuối - ví dụ:

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

Làm cách nào để bao gồm các khoảng trống ở cuối trong kết quả độ dài?


1
Tôi nghĩ giải pháp thực sự ở đây có thể là Microsoft sửa phần mềm bị hỏng của họ. Bỏ phiếu tại đây: feedback.azure.com/forums/908035-sql-server/suggestions/…
QA Collective,

Câu trả lời:


125

Điều này được Microsoft ghi lại rõ ràng trong MSDN tại http://msdn.microsoft.com/en-us/library/ms190329(SQL.90).aspx , trong đó LEN "trả về số ký tự của biểu thức chuỗi được chỉ định, loại trừ ô trống theo sau ”. Tuy nhiên, đây là một chi tiết dễ bỏ sót nếu bạn không cảnh giác.

Thay vào đó, bạn cần sử dụng hàm DATALENGTH - xem http://msdn.microsoft.com/en-us/library/ms173486(SQL.90).aspx - "trả về số byte được sử dụng để biểu diễn bất kỳ biểu thức nào".

Thí dụ:

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
LƯU Ý: Đối với DATALENGTHbạn, bạn cũng sẽ cần chia kết quả cho 2 nếu biểu thức đang được kiểm tra là loại ký tự rộng (Unicode; nchar, nvarchar hoặc ntext), vì kết quả là byte chứ không phải ký tự .
devstuff

7
Ngoài ra đối với varcharvv điều này có thể phụ thuộc đối chiếu và thậm chí không phải phép chia thẳng cho 2 là đáng tin cậy. Xem ví dụ ở đây
Martin Smith

18
Tôi sẽ sử dụng LEN(REPLACE(expr, ' ', '_')). Điều này sẽ hoạt động với varcharnvarcharvà các chuỗi chứa các ký tự điều khiển unicode đặc biệt.
Olivier Jacot-Descombes

6
-1, DATALENGTH()không nên được coi là một cách thay thế để đếm ký tự vì nó đếm byte thay vì ký tự và điều này quan trọng khi đại diện cho cùng một chuỗi trong VARCHAR/ NVARCHAR.
binki,

5
Bắt đầu từ SQL server 2012, các cột unicode với các đối chiếu phiên bản 100 hiện hỗ trợ các cặp thay thế. Điều này có nghĩa là một ký tự duy nhất có thể sử dụng tới 4 byte, khiến cho phép chia cho hai không thành công. Xem msdn .
Frédéric

85

Bạn có thể sử dụng thủ thuật này:

LEN (Str + 'x') - 1


15
Bạn có thể cho chúng tôi biết các lựa chọn thay thế tốt hơn không? Độ mạnh dữ liệu chắc chắn là không.
Serge

15
Tôi thực sự không đồng ý rằng sử dụng một phương pháp không nhất quán (trong một số trường hợp bạn chia kết quả của nó cho 2 và đôi khi không) là một lựa chọn tốt hơn. Tuy nhiên, có lẽ có một hiệu suất gần bằng không với phương pháp của tôi.
Serge

5
Phương pháp của @usr Serge là tốt nhất, IMHO. Đơn giản và thanh lịch. DATALENGTH phức tạp: phụ thuộc kiểu byte đơn / byte kép, phụ thuộc đối chiếu / ngôn ngữ, v.v.
Ông TA

10
Đây là giải pháp tốt nhất, thanh lịch cho đến nay. Tôi không thực sự quan tâm đến việc nó có CẢM THẤY như hack hay không (viết mã không phải là về cảm giác), tôi thực sự quan tâm đến thực tế là giải pháp này không có tác dụng phụ. Tôi có thể thay đổi kiểu dữ liệu varchar / nvarchar và nó vẫn hoạt động. Làm tốt lắm.
Mike Keskinov

5
Có một cảnh báo vì tác dụng phụ này. Nếu bạn đang làm việc với một biến kiểu nvarchar (4000) và biến của bạn chứa chuỗi ký tự 4000, thì ký tự được thêm vào sẽ bị bỏ qua và bạn sẽ nhận được kết quả sai (SQL's len bỏ qua dấu cách ở cuối, trừ đi 1 bạn trừ).
hatchhet - thực hiện với SOverflow

17

Tôi sử dụng phương pháp này:

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

Tôi thích điều này hơn DATALENGTH vì điều này hoạt động với các kiểu dữ liệu khác nhau và tôi thích nó hơn việc thêm một ký tự vào cuối vì bạn không phải lo lắng về trường hợp cạnh khi chuỗi của bạn đã ở độ dài tối đa.

Lưu ý: Tôi sẽ kiểm tra hiệu suất trước khi sử dụng nó với một tập dữ liệu rất lớn; mặc dù tôi vừa thử nghiệm nó với 2 triệu hàng và nó không chậm hơn LEN mà không có REPLACE ...


14

"Làm cách nào để bao gồm các khoảng trắng ở cuối trong kết quả độ dài?"

Bạn yêu cầu ai đó gửi yêu cầu nâng cao SQL Server / báo cáo lỗi bởi vì gần như tất cả các giải pháp được liệt kê cho vấn đề đơn giản đến kinh ngạc này ở đây đều có một số thiếu sót hoặc không hiệu quả. Điều này dường như vẫn đúng trong SQL Server 2012. Tính năng tự động cắt có thể xuất phát từ ANSI / ISO SQL-92 nhưng dường như có một số lỗ hổng (hoặc thiếu tính toán chúng).

Vui lòng bỏ phiếu "Thêm cài đặt để LEN tính khoảng trắng ở cuối" tại đây:

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

Liên kết Retired Connect: https://connect.microsoft.com/SQLServer/feedback/details/801381


2
Các datalengthgiải pháp được thậm chí tệ hơn bắt đầu từ SQL server 2012, vì nó bây giờ không hỗ trợ cặp thay thế trong UTF-16, có nghĩa là một nhân vật có thể sử dụng lên đến 4 byte. Thực sự đã đến lúc họ sửa lenchức năng để tuân thủ ANSI, hoặc ít nhất là cung cấp một chức năng chuyên dụng để đếm ký tự bao gồm dấu cách ở cuối.
Frédéric

1
Liên kết phản hồi cần được sử dụng nhiều hơn cho việc này. Thật khó hiểu là vấn đề này chỉ có thể được tìm kiếm qua internet. Tôi đã dành gần 2 giờ để cố gắng tìm ra vị trí mà tôi đã mắc lỗi trong mã của riêng mình trước khi xem xét rằng hàm LEN () là nguyên nhân khiến tôi bị ngắt kết nối.
Takophiliac

Tôi đồng ý với điều này nhưng nên cho phép một tham số cắt bỏ khoảng trắng .. vì nó làm cho việc so sánh chuỗi với EF dễ dàng hơn rất nhiều, không phải kiểm tra xem có bao gồm khoảng trắng hay không khi biểu thức truy vấn được tạo.
ganjeii

9

Có vấn đề với hai câu trả lời được bình chọn nhiều nhất. Câu trả lời đề xuất DATALENGTHlà dễ bị lỗi của lập trình viên. Kết quả của DATALENGTHphải được chia cho 2 cho NVARCHARcác loại, nhưng không chia cho VARCHARcác loại. Điều này đòi hỏi kiến ​​thức về loại mà bạn đang sử dụng và nếu loại đó thay đổi, bạn phải siêng năng thay đổi những nơi bạn đã sử dụng DATALENGTH.

Ngoài ra còn có một vấn đề với câu trả lời được ủng hộ nhiều nhất (mà tôi thừa nhận là cách ưa thích của tôi để làm điều đó cho đến khi vấn đề này khiến tôi khó chịu). Nếu thứ mà bạn đang nhận có độ dài là kiểu NVARCHAR(4000)và nó thực sự chứa một chuỗi 4000 ký tự, SQL sẽ bỏ qua ký tự được nối thêm thay vì truyền ngầm kết quả đến NVARCHAR(MAX). Kết quả cuối cùng là độ dài không chính xác. Điều tương tự cũng sẽ xảy ra với VARCHAR (8000).

Những gì tôi đã tìm thấy hoạt động, gần như nhanh như cũ LEN, nhanh hơn LEN(@s + 'x') - 1đối với các chuỗi lớn và không giả định chiều rộng ký tự bên dưới là như sau:

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

Điều này nhận được độ dài dữ liệu, và sau đó chia cho độ dài dữ liệu của một ký tự duy nhất từ ​​chuỗi. Phần phụ của 'x' bao gồm trường hợp chuỗi trống (sẽ cung cấp số chia cho 0 trong trường hợp đó). Điều này hoạt động cho dù @sVARCHARhoặc NVARCHAR. Thực hiện LEFTký tự của 1 trước khi phần nối thêm bị cắt bớt một lúc khi chuỗi lớn. Tuy nhiên, vấn đề với điều này là nó không hoạt động chính xác với các chuỗi chứa các cặp thay thế.

Có một cách khác được đề cập trong một bình luận cho câu trả lời được chấp nhận, sử dụng REPLACE(@s,' ','x'). Kỹ thuật đó đưa ra câu trả lời chính xác, nhưng chậm hơn một vài bậc về độ lớn so với các kỹ thuật khác khi chuỗi lớn.

Với các vấn đề được đưa ra bởi các cặp thay thế trên bất kỳ kỹ thuật nào sử dụng DATALENGTH, tôi nghĩ rằng phương pháp an toàn nhất đưa ra câu trả lời chính xác mà tôi biết là:

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

Điều này nhanh hơn REPLACEkỹ thuật và nhanh hơn nhiều với các chuỗi dài hơn. Về cơ bản kỹ thuật này là LEN(@s + 'x') - 1kỹ thuật, nhưng với sự bảo vệ cho trường hợp cạnh trong đó chuỗi có độ dài 4000 (đối với nvarchar) hoặc 8000 (đối với varchar), do đó câu trả lời chính xác được đưa ra ngay cả cho điều đó. Nó cũng phải xử lý các chuỗi với các cặp thay thế một cách chính xác.


1
Thật không may, câu trả lời này không còn hoạt động đối với các chuỗi chứa các cặp thay thế trong SQL Server 2012. Chạy hoạt động của bạn trên N'x𤭢x' COLLATE Latin1_General_100_CI_AS_SCcho kết quả 4, trong khi LENcho kết quả là 3.
Douglas

9
@Douglas - Đó là thông tin hữu ích. Giá như Microsoft chỉ cung cấp cho chúng ta một phiên bản LEN không bỏ qua dấu cách ở cuối.
hatchhet - được thực hiện với SOverflow

5

Bạn cũng cần đảm bảo rằng dữ liệu của bạn thực sự được lưu với các ô trống ở cuối. Khi ANSI PADDING TẮT (không phải mặc định):

Các khoảng trống ở cuối trong các giá trị ký tự được chèn vào cột varchar sẽ được cắt bớt.


3
Tôi nghĩ bạn không nên tắt ANSI PADDING vì cài đặt này đã lỗi thời. Có nó ở một giá trị không chuẩn gây ra nhiều vấn đề nhỏ.
usr

4

LEN cắt các khoảng trắng ở cuối theo mặc định, vì vậy tôi thấy điều này hoạt động khi bạn di chuyển chúng lên phía trước

(LEN (REVERSE (TestField))

Vì vậy, nếu bạn muốn, bạn có thể nói

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)

Tất nhiên, không sử dụng điều này cho không gian hàng đầu.


9
Bây giờ nó cắt các khoảng trắng đầu thay vì các khoảng trắng ở cuối. Cùng ngày, vấn đề khác nhau :)
đảo ngược kỹ sư

@DaveBoltman Đề xuất của tôi có lẽ vẫn còn phức tạp hơn, nhưng bạn cũng có thể so sánh với độ dài TRIM'ed.
Brian J,

Điều này khắc phục lỗi trong đó các khoảng trắng đầu không được tính thay vì các khoảng trắng ở cuối. Xem đoạn mã sau: 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

Bạn nên xác định một hàm CLR trả về trường Độ dài của chuỗi, nếu bạn không thích việc nối chuỗi. Tôi sử dụng LEN('x' + @string + 'x') - 2trong các trường hợp sử dụng sản xuất của mình.


0

Nếu bạn không thích DATALENGTHvì lo ngại n / varchar, hãy làm thế nào về:

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

đó chỉ là

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

được bọc bằng bảo vệ chia cho-không.

Bằng cách chia cho DATALENGTH của một ký tự, chúng ta nhận được độ dài được chuẩn hóa.

(Tất nhiên, vẫn có vấn đề với các cặp thay thế nếu đó là mối quan tâm.)


-4

sử dụng SELECT DATALENGTH ('string')


2
bạn chỉ trình bày lại câu trả lời của người khác từ 7 năm trước và nhà cung cấp không có gì mới hoặc thậm chí giải thích những gì bạn trả lời hoặc cách nó trả lời câu hỏi đó.
Jpsh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.