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

T-SQL如何解析文本并提取与标题编号对应的独立段落

T-SQL 拆分带编号文本并关联对应段落编号的实现方案

原来的方案存在两个核心问题:

  • 硬编码替换单数字编号的逻辑会误命中小数(如1.3里的1.),同时替换后直接丢失了原编号的数值信息,无法做关联
  • 无法区分开头无编号的前置段落和后续带编号的段落,靠行号推算编号必然出错

以下是可直接运行的实现代码,完全匹配你给出的预期输出:

DECLARE @EXAMPLE TABLE (
      ID INT
    , COMMENT VARCHAR(8000)
    )

INSERT INTO @EXAMPLE (ID, COMMENT)
VALUES
    (1, '1. Sed ut perspiciatis 1.3 unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. 2. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. 3. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem 4. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur 5. Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?')
    , (2, 'At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia 8.3 deserunt mollitia animi, id est laborum et dolorum fuga')
    , (3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua 1. A cras semper auctor neque 2. Morbi tincidunt augue interdum velit euismod in')
    , (4, '1. Amet luctus venenatis lectus magna 2. Magna ac placerat vestibulum lectus mauris ultrices eros in cursus 3. Et ligula ullamcorper malesuada proin libero nunc consequat interdum varius 4. Enim facilisis gravida neque convallis a 5. Sed lectus vestibulum mattis ullamcorper velit sed 6. Vel turpis nunc eget lorem dolor 7. Convallis convallis tellus id interdum velit laoreet id donec 8. Nibh tortor id aliquet lectus proin nibh nisl 9. Eu ultrices vitae auctor eu augue ut 10. Mus mauris vitae ultricies leo integer malesuada nunc 11. Viverra justo nec 10.4 ultrices dui sapien eget mi 12. Tristique senectus et netus et malesuada fames ac turpis')

;WITH RECURSIVE_SPLIT AS (
    -- 锚点成员:初始化每条记录的处理状态
    SELECT 
        ID,
        COMMENT AS REMAINING_TEXT,
        CAST(NULL AS INT) AS CURRENT_SECTION_NUM,
        CAST(NULL AS VARCHAR(8000)) AS CURRENT_SECTION,
        0 AS IS_FIRST_PASS
    FROM @EXAMPLE

    UNION ALL

    SELECT
        ID,
        -- 截掉已处理部分后的剩余文本
        CASE 
            WHEN PATINDEX('%[0-9]%. %', REMAINING_TEXT) = 0 THEN ''
            ELSE SUBSTRING(REMAINING_TEXT, PATINDEX('%[0-9]%. %', REMAINING_TEXT) + CHARINDEX('. ', REMAINING_TEXT, PATINDEX('%[0-9]%. %', REMAINING_TEXT)) +1, 8000)
        END,
        -- 提取当前匹配到的编号
        CASE
            -- 首次处理且开头没有编号,编号设为0
            WHEN IS_FIRST_PASS = 0 AND PATINDEX('[0-9]%. %', REMAINING_TEXT) <> 1 THEN 0
            ELSE CAST(SUBSTRING(REMAINING_TEXT, PATINDEX('%[0-9]%. %', REMAINING_TEXT), CHARINDEX('. ', REMAINING_TEXT, PATINDEX('%[0-9]%. %', REMAINING_TEXT)) - PATINDEX('%[0-9]%. %', REMAINING_TEXT)) AS INT)
        END,
        -- 提取当前段落内容
        CASE
            WHEN IS_FIRST_PASS = 0 AND PATINDEX('[0-9]%. %', REMAINING_TEXT) <> 1 THEN 
                LEFT(REMAINING_TEXT, ISNULL(NULLIF(PATINDEX('%[0-9]%. %', REMAINING_TEXT)-1, -1), 8000))
            ELSE 
                LEFT(REMAINING_TEXT, ISNULL(NULLIF(PATINDEX('%[0-9]%. %', SUBSTRING(REMAINING_TEXT, CHARINDEX('. ', REMAINING_TEXT, PATINDEX('%[0-9]%. %', REMAINING_TEXT)) + 2, 8000)) + CHARINDEX('. ', REMAINING_TEXT, PATINDEX('%[0-9]%. %', REMAINING_TEXT)) , 0), 8000))
        END,
        1 AS IS_FIRST_PASS
    FROM RECURSIVE_SPLIT
    WHERE REMAINING_TEXT <> ''
)
-- 输出最终结果,过滤掉初始化的空行
SELECT 
    ID,
    CURRENT_SECTION_NUM AS SECTION_NUMBER,
    TRIM(CURRENT_SECTION) AS SECTION
FROM RECURSIVE_SPLIT
WHERE CURRENT_SECTION IS NOT NULL
ORDER BY ID, 
    -- 保证段落顺序正确:0号段落排在最前,之后按编号排序
    CASE WHEN CURRENT_SECTION_NUM = 0 THEN 0 ELSE 1 END,
    CURRENT_SECTION_NUM

方案优势

  • 用PATINDEX匹配[数字]. 的模式,自动适配1位、2位甚至更多位的编号,不需要硬编码所有可能的编号值
  • 匹配时会判断模式位置,不会把1.3、8.3这类小数里的点误判为段落编号分隔符
  • 自动识别开头无编号的段落,赋值为SECTION_NUMBER = 0,完全符合需求
  • 直接从原文本中提取编号值作为段落编号,不需要靠行号推算,和原文本的编号完全对应

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:30:04