我正在尝试计算写在表格列中的文字。因此我使用以下查询。
SELECT LEN(ExtractedText) -
LEN(REPLACE(ExtractedText, ' ', '')) + 1 from EDDSDBO.Document where ID='100'.
我收到的错误结果很高。 另一方面,如果我将文本直接复制到声明中,那么它就可以工作,即
SELECT LEN('blablabla text') - LEN(REPLACE('blablabla text', ' ', '')) + 1.
现在数据类型为nvarchar(max)
,因为文本很长。我已尝试将列转换为text
或ntext
并应用datalength()
而不是len()
。尽管如此,我获得了相同的结果,它确实可以用作字符串,但不能从表中工作。
答案 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>
<强>更新强>
这是一个使用CTEs和ranking来消除额外空格的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