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

当我尝试使用SQL Server LEN()函数查找TestField的长度时,它不计算尾随空格-例如:

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

Answers:


125

Microsoft在MSDN中清楚地记录了这一点,网址为 http://msdn.microsoft.com/zh-cn/library/ms190329(SQL.90).aspx中,其中指出LEN“返回指定字符串表达式的字符数,不包括尾随空白”。但是,如果您不警惕,这是一个容易错过的细节。

您需要改为使用DATALENGTH函数-请参阅 http://msdn.microsoft.com/zh-cn/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如果要测试的表达式是宽字符类型(Unicode; nchar,nvarchar或ntext),您还需要将结果除以2,因为结果以字节单位,而不是characters
devstuff,2010年

7
同样对于varchar等等,这可能取决于排序规则,即使直接除以2也不可靠。在此处
Martin Smith,

18
我会用LEN(REPLACE(expr, ' ', '_'))。这应该与varcharnvarchar和包含特殊unicode控制字符的字符串一起使用。
Olivier Jacot-Descombes 2014年

6
-1 DATALENGTH()不应该被视为计数字符的另一种方法,因为它计数字节而不是字符,并且在VARCHAR/中表示相同的字符串时很重要NVARCHAR
2014年

5
从SQL Server 2012开始,具有100个排序规则的unicode列现在支持代理对。这意味着单个字符最多可以使用4个字节,从而导致除法二招失败。参见msdn
2015年

85

您可以使用以下技巧:

LEN(Str +'x')-1


15
请您给我们更好的选择启发我们吗?数据长度肯定不是。
Serge 2013年

15
我强烈不同意使用不一致的方法(在某些情况下,将其结果除以2,有时不除以2)是更好的选择。我的方法也许对性能的影响几乎为零。
Serge 2013年

5
@usr Serge的方法是最好的,恕我直言。简洁大方。DATALENGTH复杂:单/双字节类型依赖,整理/语言依赖,等等
大先生

10
到目前为止,这是最好的,优雅的解决方案。我真的不在乎它是否像黑客一样(编码与感觉无关),我真的很在乎这个解决方案没有副作用。我可以更改数据类型varchar / nvarchar,但它仍然有效。做得好。
Mike Keskinov 2014年

5
有一个警告,因为这种副作用。如果您使用的是nvarchar(4000)类型的变量,并且变量包含4000字符串,则添加的字符将被忽略,并且会得到错误的结果(SQL的len忽略尾随空格,请减去1您减去)。
柴刀-SOverflow

17

我使用这种方法:

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

我比较喜欢DATALENGTH,因为它适用于不同的数据类型,而且我更喜欢在结尾添加字符,因为您不必担心字符串已经达到最大长度的边缘情况。

注意:在针对非常大的数据集使用性能之前,我会先对其进行测试;虽然我只是针对200万行进行了测试,但没有REPLACE的情况,它没有LEN慢...


14

“如何在长度结果中包括尾随空格?”

您可以要求某人提交SQL Server增强请求/错误报告,因为几乎所有列出的针对此惊人的简单问题的变通办法都存在某些缺陷或效率低下。这在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

退休的Connect链接:https : //connect.microsoft.com/SQLServer/feedback/details/801381


2
datalength从SQL Server 2012开始,此解决方案甚至更糟,因为它现在支持UTF-16中的代理对,这意味着一个字符最多可以使用4个字节。实际上是他们修复len符合ANSI 的功能的时候了,或者至少提供了一个用于计算包括尾随空格在内的char的专用功能。
弗雷德里克2015年

1
为此,需要更多使用反馈链接。令人困惑的是只能通过互联网搜索此问题。在考虑甚至LEN()函数是导致我断开连接的原因之前,我花了将近2个小时试图弄清楚自己的代码在哪里出错。
Takophiliac

我同意这一点,但是应该允许使用参数来剪裁空白..因为它使与EF的字符串比较容易得多,而无需在构建iqueryable表达式时检查是否包含空白。
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”的附加项覆盖字符串为空的情况(在这种情况下,该值将被零除)。不管@sVARCHAR还是都有效NVARCHARLEFT当字符串很大时,在追加之前做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。
道格拉斯

9
@Douglas-这是有用的信息。如果仅Microsoft会给我们提供不忽略尾随空格的LEN版本。
柴刀-SOverflow

5

您还需要确保您的数据实际以尾随空白保存。当ANSI PADDING为OFF(非默认)时:

修剪插入varchar列的字符值中的尾随空白。


3
我认为您不应关闭ANSI PADDING,因为此设置已过时。将其设置为非标准值会引起许多小问题。
usr

4

LEN默认情况下会剪切尾随空格,因此当您将它们移到最前面时,我发现此功能有效

(LEN(REVERSE(TestField))

因此,如果您愿意,您可以说

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
现在,它修剪前导空格而不是尾随空格。同一天,不同的问题:)
逆向工程师

@DaveBoltman我的建议可能仍然比较复杂,但是您可以将其与TRIM的长度进行比较。
布赖恩·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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.