SQL:使用len()的问题字数

时间:2011-08-11 07:40:50

标签: sql sql-server tsql

我正在尝试计算写在表格列中的文字。因此我使用以下查询。

SELECT LEN(ExtractedText) - 
LEN(REPLACE(ExtractedText, ' ', '')) + 1 from EDDSDBO.Document where ID='100'.

我收到的错误结果很高。 另一方面,如果我将文本直接复制到声明中,那么它就可以工作,即

SELECT LEN('blablabla text') - LEN(REPLACE('blablabla text', ' ', '')) + 1.

现在数据类型为nvarchar(max),因为文本很长。我已尝试将列转换为textntext并应用datalength()而不是len()。尽管如此,我获得了相同的结果,它确实可以用作字符串,但不能从表中工作。

4 个答案:

答案 0 :(得分:2)

你在计算空格而不是单词。这通常会产生一个近似的答案。

e.g。

'  this     string    will    give an    incorrect      result   '

尝试这种方法:http://www.sql-server-helper.com/functions/count-words.aspx

CREATE FUNCTION [dbo].[WordCount] ( @InputString VARCHAR(4000) ) 
RETURNS INT
AS
BEGIN

DECLARE @Index          INT
DECLARE @Char           CHAR(1)
DECLARE @PrevChar       CHAR(1)
DECLARE @WordCount      INT

SET @Index = 1
SET @WordCount = 0

WHILE @Index <= LEN(@InputString)
BEGIN
    SET @Char     = SUBSTRING(@InputString, @Index, 1)
    SET @PrevChar = CASE WHEN @Index = 1 THEN ' '
                         ELSE SUBSTRING(@InputString, @Index - 1, 1)
                    END

    IF @PrevChar = ' ' AND @Char != ' '
        SET @WordCount = @WordCount + 1

    SET @Index = @Index + 1
END

RETURN @WordCount

END
GO

用法

DECLARE @String VARCHAR(4000)
SET @String = 'Health Insurance is an insurance against expenses incurred through illness of the insured.'

SELECT [dbo].[WordCount] ( @String )

答案 1 :(得分:1)

前导空格,尾随空格,相邻单词之间的两个或多个空格 - 这些可能是导致错误结果的原因。

函数LTRIM()RTRIM()可以帮助您消除前两个问题。至于第三个,您可以使用REPLACE(ExtractedText, ' ', ' ')将双空格替换为单个空格,但我不确定您是否没有三个空格(在这种情况下,您需要重复替换)。 / p>


<强>更新

这是一个使用CTEsranking来消除额外空格的UDF,然后计算剩余的空格以将数量作为单词数返回:

CREATE FUNCTION fnCountWords (@Str varchar(max))
RETURNS int
AS BEGIN
  DECLARE @xml xml, @res int;
  SET @Str = RTRIM(LTRIM(@Str));
  WITH split AS (
    SELECT
      idx = number,
      chr = SUBSTRING(@Str, number, 1)
    FROM master..spt_values
    WHERE type = 'P'
      AND number BETWEEN 1 AND LEN(@Str)
  ),
  ranked AS (
    SELECT
      idx,
      chr,
        rnk = idx - ROW_NUMBER() OVER (PARTITION BY chr ORDER BY idx)
      FROM split
  )
  SELECT @res = COUNT(DISTINCT rnk) + 1
  FROM ranked
  WHERE chr = ' ';
  RETURN @res;
END

使用此功能,您的查询将完全如下:

SELECT fnCountWords(ExtractedText)
FROM EDDSDBO.Document
WHERE ID='100'

更新2

该函数使用其中一个系统表master..spt_values作为计数表。使用的特定子集仅包含0到2047之间的值。这意味着对于长度超过2047个字符的输入(在修剪前导和尾随空格之后),该函数将无法正常工作,正如@ t-clausen.dk在其注释中正确指出的那样。因此,如果可以使用更长的输入字符串,则应使用自定义tally table

答案 2 :(得分:1)

将空格替换为文本中从未出现过的内容,例如'$!'或者选择另一个值。 然后替换所有'$! '和'$!'没有这种方式,你在一个单词之后永远不会有超过1个空格。然后使用您当前的脚本。我已将一个单词定义为空格,后跟非空格。

这是一个例子

DECLARE @T TABLE(COL1 NVARCHAR(2000), ID INT)

INSERT @T VALUES('A B  C   D', 100)

SELECT LEN(C) - LEN(REPLACE(C,' ', '')) COUNT FROM (
SELECT REPLACE(REPLACE(REPLACE(' ' + COL1, ' ', ' $!'), '$! ',''), '$!', '') C
FROM @T ) A

这是一个递归解决方案

DECLARE @T TABLE(COL1 NVARCHAR(2000), ID INT)

INSERT @T VALUES('A B  C   D', 100)
INSERT @T VALUES('have a nice day with 7 words', 100)

;WITH CTE AS
(
SELECT 1 words, col1 c, col1 FROM @t WHERE id = 100
UNION ALL
SELECT words +1, right(c, len(c) - patindex('% [^ ]%', c)), col1 FROM cte
WHERE patindex('% [^ ]%', c) > 0
)
SELECT words, col1 FROM cte WHERE patindex('% [^ ]%', c) = 0

答案 3 :(得分:0)

您应该使用varchar数据类型声明列,例如:

create table emp(ename varchar(22));

insert into emp values('amit');

select ename,len(ename) from emp;
  

输出:4