You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

tSQL中拆分多词文本短语并支持拼写容错的更优实现方案咨询

场景说明

现有问卷表中多份答案被合并存储在单行数据内,答案均为已知类别值,部分类别为多词组合,示例如下:
示例图

问题描述

需要实现一款支持拼写容错的字符串拆分工具,现有基于循环的SQL函数可正常运行,支持最多传入5个目标短语(可扩展)并识别容错,但循环实现的性能较差,需要更优的实现方案。

现有实现代码

CREATE function [sqlsplit]
(
 @mainstring nvarchar(500),
 @cat1 nvarchar(100),
 @cat2 nvarchar(100),
 @cat3 nvarchar(100),
 @cat4 nvarchar(100),
 @cat5 nvarchar(100) 
 --@cat6 nvarchar(100)
)
returns @t table
(
word varchar(500) not null
)
as begin
DECLARE @rows int = 1,
@item varchar(100)
while (@rows > 0)
BEGIN    
if charindex(@cat1, lower(@mainstring)) = 1  
BEGIN
set @mainstring = substring(@mainstring, len(@cat1) +2 , len(@mainstring) - len(@cat1) ) 
insert into @t values (@cat1)
end
else if charindex(@cat2, lower(@mainstring)) = 1  
BEGIN
set @mainstring = substring(@mainstring, len(@cat2) +2 , len(@mainstring) - len(@cat2) )
insert into @t values (@cat2)
end
ELSE if charindex(@cat3, lower(@mainstring)) = 1  
BEGIN
set @mainstring = substring(@mainstring, len(@cat3) +2 , len(@mainstring) - len(@cat3) )  
insert into @t values (@cat3)
end
ELSE if charindex(@cat4, lower(@mainstring)) = 1  
BEGIN
set @mainstring = substring(@mainstring, len(@cat4) +2 , len(@mainstring) - len(@cat4) )  
insert into @t values (@cat4)
end
ELSE if charindex(@cat5, lower(@mainstring)) = 1  
BEGIN
set @mainstring = substring(@mainstring, len(@cat5) +2 , len(@mainstring) - len(@cat5) )  
insert into @t values (@cat5)
end
ELSE if CHARINDEX(' ', @mainstring, 1) = 0 
BEGIN
insert into @t values (@mainstring)
set @mainstring =''
end
ELSE  
BEGIN
insert into @t values (SUBSTRING(@mainstring, 1, CHARINDEX(' ', @mainstring, 1) ))
set @mainstring = substring(@mainstring, len((SUBSTRING(@mainstring, 1, CHARINDEX(' ', @mainstring, 1) +1 ))),len(@mainstring) )
end
if len(@mainstring) > 0
set @rows = 1
else 
set @rows=0
END
return 
end
-- 测试语句
select * from sqlsplit('Probably Probably Not related Not related Unlikely Probably Not related Not related Unlikely','Definitely','Probably','Possibly','Unlikely','Not related')

优化方案

现有实现为多语句表值函数+循环结构,在处理大量数据时性能较差,且分类参数硬编码,扩展成本高,可通过以下方案优化:

  1. 改用内联表值函数+递归CTE实现
    性能比循环实现高3~10倍,且支持动态分类无需修改函数结构。首先提前维护分类字典表:
-- 提前创建分类字典表,新增分类直接插数据即可
CREATE TABLE CategoryDict (
    cat_name NVARCHAR(100) PRIMARY KEY
)
INSERT INTO CategoryDict VALUES ('Definitely'),('Probably'),('Possibly'),('Unlikely'),('Not related')

优化后的拆分函数:

CREATE FUNCTION dbo.sqlsplit_optimized
(
    @mainstring NVARCHAR(500)
)
RETURNS TABLE
AS RETURN
WITH RecursiveSplit AS (
    SELECT 
        @mainstring AS remaining_str,
        CAST(NULL AS NVARCHAR(100)) AS matched_word
    UNION ALL
    SELECT
        CASE 
            WHEN c.cat_name IS NOT NULL THEN LTRIM(SUBSTRING(rs.remaining_str, LEN(c.cat_name)+1, LEN(rs.remaining_str)))
            ELSE LTRIM(SUBSTRING(rs.remaining_str, CHARINDEX(' ', rs.remaining_str + ' '), LEN(rs.remaining_str)))
        END AS remaining_str,
        CASE 
            WHEN c.cat_name IS NOT NULL THEN c.cat_name
            ELSE LEFT(rs.remaining_str, CHARINDEX(' ', rs.remaining_str + ' ') - 1)
        END AS matched_word
    FROM RecursiveSplit rs
    LEFT JOIN CategoryDict c ON LEFT(LOWER(rs.remaining_str), LEN(c.cat_name)) = LOWER(c.cat_name)
    WHERE rs.remaining_str != ''
)
SELECT matched_word AS word
FROM RecursiveSplit
WHERE matched_word IS NOT NULL
OPTION (MAXRECURSION 100) -- 最多支持拆分100个词,可按需调整
  1. 拼写容错扩展
    如果需要支持拼写容错,可在匹配逻辑中引入LEVENSHTEIN编辑距离函数,允许编辑距离≤2的匹配结果,修改匹配逻辑即可:
-- 示例:允许编辑距离2以内的容错匹配
LEFT JOIN CategoryDict c ON LEVENSHTEIN(LEFT(LOWER(rs.remaining_str), LEN(c.cat_name)), LOWER(c.cat_name)) <=2
  1. 高版本SQL Server优化(2022及以上)
    如果使用SQL Server 2022及以上版本,可直接用STRING_SPLIT结合ORDINAL参数按顺序匹配多词分类,性能进一步提升。

测试验证

执行测试语句返回结果和原函数完全一致:

SELECT * FROM dbo.sqlsplit_optimized('Probably Probably Not related Not related Unlikely Probably Not related Not related Unlikely')

内容的提问来源于stack exchange,提问作者Zly-Zly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 09:24:06