提取编号间内容SQL查询


date: 2026-05-07 updated: 2026-05-07 conversation_id: 322e662d-d604-4bf0-aaf0-2c7a8cfe831f title: "提取编号间内容SQL查询" tags: [deepseek, conversation] ---

提取编号间内容SQL查询

创建时间: 2026-05-07 16:12

👤 用户:

1、浙江纳微年产600吨生物层析介质和2手性药物分离纯化项目 2、补充流动资金

以上字段为T_STK159表中的f009字段内容,我需要1、与2、之间的内容,应该如何查询 mysql


💭 思考过程

我们理解用户有一个MySQL表T_STK159,其中字段f009存储了类似"1、浙江纳微年产600吨生物层析介质和2手性药物分离纯化项目\n2、补充流动资金"这样的文本。用户需要提取"1、"和"2、"之间的内容,即第一个编号和第二个编号之间的部分。在这个例子中,应该是"浙江纳微年产600吨生物层析介质和"(注意原文本中"2手性药物"没有顿号?)实际上原文:"1、浙江纳微年产600吨生物层析介质和2手性药物分离纯化项目"然后换行"2、补充流动资金",所以"1、"之后到"2、"之前的内容是"浙江纳微年产600吨生物层析介质和"。注意"和2"中的"和"字属于前一部分,因为"2"是第二个项目的开始。所以需要提取的是第一个项目名称。

用户问"应该如何查询",需要给出SQL语句。MySQL中可以使用字符串函数:LOCATE, SUBSTRING。也可以使用正则表达式REGEXP_SUBSTR(MySQL 8.0+)。考虑到可能是MySQL 5.x,最好用基础函数。

假设我们要从f009中提取第一个编号(以数字+、开头)和第二个编号之间的子串。编号格式可能是"数字、"或"数字."?但用户给出的是"1、"和"2、"。

通用方法:找到第一个"1、"之后的位置,然后找到下一个"2、"的位置,截取中间部分。注意可能会有多个项目,用户只需要第一个和第二个之间的内容。

SQL示例:

SELECT SUBSTRING( f009, LOCATE('1、', f009) + LENGTH('1、'), LOCATE('2、', f009) - (LOCATE('1、', f009) + LENGTH('1、')) ) AS extractedcontent FROM TSTK159;

但需要确保存在"1、"和"2、"。若不存在则返回空。另外注意可能编号前有换行或其他字符,但LOCATE能处理。

更稳健的做法:使用正则表达式提取。MySQL 8+有REGEXPSUBSTR: SELECT REGEXPSUBSTR(f009, '(?<=1、).*?(?=2、)') AS extracted FROM T_STK159;

但注意正则需要支持lookaround,MySQL的REGEXPSUBSTR默认不支持?<=。可以用捕获组:REGEXPSUBSTR(f009, '1、(.*?)2、', 1, 1, '', 1)

或者使用SUBSTRING_INDEX结合。但简单的字符串函数即可。

用户要求输出答案,需要提供SQL查询语句。同时解释一下。

我将给出两种方法:基本字符串函数和正则表达式(如果版本支持)。

要从 T_STK159 表的 f009 字段中提取 1、2、 之间的内容(即第一个项目名称),可以使用 MySQL 的字符串函数或正则表达式。以下是两种常用方法:

方法一:使用 LOCATESUBSTRING(兼容 MySQL 5.x 及更高版本)

SELECT 
    SUBSTRING(
        f009,
        LOCATE('1、', f009) + CHAR_LENGTH('1、'),
        LOCATE('2、', f009) - (LOCATE('1、', f009) + CHAR_LENGTH('1、'))
    ) AS project_name
FROM T_STK159
WHERE f009 LIKE '%1、%2、%';

说明

  • LOCATE('1、', f009) 找到第一个编号的起始位置。
  • LOCATE('2、', f009) 找到第二个编号的起始位置。
  • 两者相减并扣除 '1、' 的长度,得到中间部分的长度。
  • CHAR_LENGTH 替代 LENGTH 以兼容多字节字符(如中文)。
  • WHERE 子句确保数据中包含两个编号,避免负数长度错误。

方法二:使用正则表达式(MySQL 8.0+ 支持)

SELECT 
    REGEXP_SUBSTR(f009, '1、\\K.*?(?=2、)') AS project_name
FROM T_STK159;

或使用捕获组:

SELECT 
    REGEXP_SUBSTR(f009, '1、(.*?)2、', 1, 1, '', 1) AS project_name
FROM T_STK159;

说明

  • \\K 忽略已匹配的部分,(?=2、) 是正向预查,提取中间内容。
  • 第二个写法中 , 1, 1, '', 1 表示返回第一个捕获组的内容。

示例数据

假设 f009 值为:

1、浙江纳微年产600吨生物层析介质和2手性药物分离纯化项目
2、补充流动资金

提取结果为:浙江纳微年产600吨生物层析介质和(注意结尾的“和”属于第一个项目名称)。

注意事项

  • 如果 1、2、 之间没有内容(如 1、、2、),结果为空字符串。
  • 如果数字编号后不是顿号而是其他符号(如 1.1、 有空格),需调整匹配模式。
  • 此查询仅提取第一个编号和第二个编号之间的部分,不会包含编号本身。

👤 用户:

并在末尾加一个等字


💭 思考过程

我们理解了用户需求:用户希望从字段中提取 '1、' 与 '2、' 之间的内容,并在末尾加一个“等”字。也就是提取出的字符串后面加上“等”。例如原字段内容为 "1、浙江纳微年产600吨生物层析介质和2手性药物分离纯化项目\n2、补充流动资金",提取出 "浙江纳微年产600吨生物层析介质和" 然后加上“等”变成 "浙江纳微年产600吨生物层析介质和等"?或者更合理的是 "浙江纳微年产600吨生物层析介质和等于"?但用户明确说“并在末尾加一个等字”,所以就是提取的内容直接拼接“等”。

注意:用户示例中提取的内容结尾有“和”,再加“等”变成“...和等”。可能需要确认是否合理,但按指令做即可。

因此,修改上面的SQL,在提取的字符串后面使用 CONCAT 添加 '等' 字。

提供修改后的查询语句。

明白了,您需要在提取 1、2、 之间的内容后,在末尾拼接一个“等”字。以下是修改后的 SQL 语句:

方法一(使用 LOCATESUBSTRING + CONCAT

SELECT 
    CONCAT(
        SUBSTRING(
            f009,
            LOCATE('1、', f009) + CHAR_LENGTH('1、'),
            LOCATE('2、', f009) - (LOCATE('1、', f009) + CHAR_LENGTH('1、'))
        ),
        '等'
    ) AS project_name_with_deng
FROM T_STK159
WHERE f009 LIKE '%1、%2、%';

方法二(使用正则表达式 MySQL 8.0+)

SELECT 
    CONCAT(
        REGEXP_SUBSTR(f009, '1、\\K.*?(?=2、)'),
        '等'
    ) AS project_name_with_deng
FROM T_STK159;

或使用捕获组:

SELECT 
    CONCAT(
        REGEXP_SUBSTR(f009, '1、(.*?)2、', 1, 1, '', 1),
        '等'
    ) AS project_name_with_deng
FROM T_STK159;

示例结果

输入:1、浙江纳微年产600吨生物层析介质和2手性药物分离纯化项目\n2、补充流动资金 输出:浙江纳微年产600吨生物层析介质和等

如果提取的内容本身就是完整的项目名称(不含“和”),例如 1、ABC项目2、,则输出 ABC项目等

👤 用户:

优化为如果有1、就以上方式处理,如果没有就不处理


💭 思考过程

我们理解需求:对字段 f009,如果存在 '1、' 模式,则提取 '1、' 和 '2、' 之间的内容并在末尾加上 '等';如果没有 '1、'(可能没有编号或只有其他格式),则保持原字段内容不变。

需要给出 MySQL 查询语句,实现条件判断。可以使用 IF 或 CASE WHEN 结合 LOCATE 判断是否存在 '1、' 和 '2、'。

用户要求:"优化为如果有1、就以上方式处理,如果没有就不处理"。不处理意味着原样输出 f009 字段。

所以最终输出应为:如果 f009 包含 '1、' 且还包含 '2、'(因为要取两者之间),则提取中间部分加'等';否则返回原 f009。

提供两种写法。

注意:如果只有 '1、' 但没有 '2、',那么无法提取,也返回原值。

给出 SQL。

好的,按照您的要求:如果字段中包含 1、(且同时需要 2、 才能提取中间内容),则提取 1、2、 之间的内容并拼接 ;否则保持原字段内容不变。

可以使用 IFCASE WHEN 结合 LOCATE 判断是否存在两个编号。以下是优化后的 SQL:

方法一:使用 IFLOCATE(兼容 MySQL 5.x)

SELECT 
    IF(
        LOCATE('1、', f009) > 0 AND LOCATE('2、', f009) > 0,
        CONCAT(
            SUBSTRING(
                f009,
                LOCATE('1、', f009) + CHAR_LENGTH('1、'),
                LOCATE('2、', f009) - (LOCATE('1、', f009) + CHAR_LENGTH('1、'))
            ),
            '等'
        ),
        f009
    ) AS result
FROM T_STK159;

方法二:使用 CASE WHEN(语义更清晰)

SELECT 
    CASE 
        WHEN LOCATE('1、', f009) > 0 AND LOCATE('2、', f009) > 0 THEN
            CONCAT(
                SUBSTRING(
                    f009,
                    LOCATE('1、', f009) + CHAR_LENGTH('1、'),
                    LOCATE('2、', f009) - (LOCATE('1、', f009) + CHAR_LENGTH('1、'))
                ),
                '等'
            )
        ELSE f009
    END AS result
FROM T_STK159;

方法三:MySQL 8.0+ 使用正则表达式 + CASE

SELECT 
    CASE 
        WHEN f009 REGEXP '1、.*2、' THEN
            CONCAT(REGEXP_SUBSTR(f009, '1、\\K.*?(?=2、)'), '等')
        ELSE f009
    END AS result
FROM T_STK159;

示例效果

  • 输入:1、浙江纳微年产600吨生物层析介质和2手性药物分离纯化项目\n2、补充流动资金

输出:浙江纳微年产600吨生物层析介质和等

  • 输入:其他文本内容,没有编号

输出:其他文本内容,没有编号

  • 输入:1、只有第一个编号但没有第二个编号

输出:原样 1、只有第一个编号但没有第二个编号

这样就实现了“有 1、 且同时有 2、 才处理,否则保留原值”的需求。

👤 用户:

SELECT s.comcode, CASE WHEN CHARLENGTH(CAST(s.F005 AS CHAR)) > 9 THEN CONCAT(FORMAT(s.F005 / 100000000, 2), '亿元') WHEN CHARLENGTH(CAST(s.F005 AS CHAR)) >= 5 THEN CONCAT(FORMAT(s.F005 / 10000, 2), '万元') ELSE CONCAT(FORMAT(s.F005, 2), '元') END AS F005, -- 通过截取最后一位来解决空格问题 CONCAT( LEFT( CASE WHEN LOCATE('1、', s.f009) > 0 AND LOCATE('2、', s.f009) > 0 THEN CONCAT( SUBSTRING( f009, LOCATE('1、', s.f009) + CHARLENGTH('1、'), LOCATE('2、', s.f009) - (LOCATE('1、', s.f009) + CHARLENGTH('1、')) ), '等' ) ELSE s.f009 END ) AS simplecontent, p.TRADECODE, p.id, p.F002, s.F009, s.F013, DATEFORMAT(s.declaredate, '%c月%e日') AS declaredate FROM TSTK159 AS s JOIN TPUB010 AS p ON s.comcode = p.f006 WHERE p.F005 = 2 AND p.F004 IN (0, 1, 9) AND p.STATE = '1' AND p.F007 = '1' AND s.F005 IS NOT NULL AND s.declaredate >= DATE_SUB(NOW(), INTERVAL 480 HOUR) ORDER BY s.declaredate DESC

1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') AS simple_content,

p.TRADECODE, p.id, p.F002, s.F009, ' at line 23

时间: 0.001s

帮我优化


💭 思考过程

我们分析错误:在第23行附近,CASE ... END 后面直接跟了 ) AS simple_content,但这里的 LEFT( 括号没有闭合。问题在于 CONCAT( LEFT( CASE ... END ) ) 缺少了 LEFT 函数的第二个参数(长度)。用户想用 LEFT 来截取最后一位解决空格问题?但代码中 LEFT( 后面只有一个参数(CASE表达式),然后就是 ) AS,这导致语法错误。

根据注释 -- 通过截取最后一位来解决空格问题,可能原意是使用 LEFT(字符串, 长度-1) 去掉最后一个字符?但注释说“截取最后一位”有点模糊。可能想用 LEFT(字符串, CHAR_LENGTH(字符串)-1) 去掉末尾的字符(比如去掉空格或特定字符)。或者想用 RIGHT 取最后一位?注释不清晰。

我们需要修复语法错误:LEFT( 需要两个参数,第二个参数是长度。用户提供的代码中是 CONCAT( LEFT( CASE ... END ) ),然后直接 AS simplecontent,没有给长度。猜测可能用户想整个提取的内容直接作为 simplecontent,不需要额外截取。或者想用 RTRIM 去除末尾空格。

鉴于错误信息指向 ) AS simplecontent 前的括号不匹配,最简单的修复是去掉外层 CONCAT( LEFT( ... ) ),直接使用内部的 CASE 表达式作为 simplecontent。如果确实需要截取最后一位,请明确需求。

用户可能原本写错了,应该是 CONCAT( LEFT( CASE ... END, 某个长度 ) ),但长度没有提供。根据注释“通过截取最后一位来解决空格问题”,可能想去掉末尾可能存在的空格?那么可以使用 RTRIM(CASE ... END) 去除尾部空格,而不是截取最后一位。

我会建议两种修复:

  1. 如果不需要额外处理,直接去掉 CONCAT(LEFT( 和对应的右括号,即 CASE ... END AS simple_content
  2. 如果要去除尾部空格,使用 RTRIM(CASE ... END) AS simple_content

提供修改后的完整 SQL。

此外,注意 CAST(s.F005 AS CHAR) 中,CHAR 应指定长度?MySQL 中 CAST(expr AS CHAR) 是可以的,但通常用 CHAR 不带长度。没问题。

现在输出修复建议。

您的 SQL 语法错误是因为 LEFT( 函数缺少第二个参数(截取长度),而且外层的 CONCATLEFT 嵌套不合理。根据注释“通过截取最后一位来解决空格问题”,推测您可能想去掉结尾的某个字符(如空格、换行等)。更合理的方法是使用 RTRIM() 去除尾部空格,或使用 TRIM(TRAILING ' ' FROM ...)。下面是修复后的 SQL,同时保持原逻辑:

SELECT
    s.comcode,
    CASE
        WHEN CHAR_LENGTH(CAST(s.F005 AS CHAR)) > 9 THEN CONCAT(FORMAT(s.F005 / 100000000, 2), '亿元')
        WHEN CHAR_LENGTH(CAST(s.F005 AS CHAR)) >= 5 THEN CONCAT(FORMAT(s.F005 / 10000, 2), '万元')
        ELSE CONCAT(FORMAT(s.F005, 2), '元')
    END AS F005,
    -- 修复:去掉错误的 LEFT/CONCAT 嵌套,直接使用 CASE 结果,并用 RTRIM 去除尾部空格
    RTRIM(
        CASE 
            WHEN LOCATE('1、', s.f009) > 0 AND LOCATE('2、', s.f009) > 0 THEN
                CONCAT(
                    SUBSTRING(
                        f009,
                        LOCATE('1、', s.f009) + CHAR_LENGTH('1、'),
                        LOCATE('2、', s.f009) - (LOCATE('1、', s.f009) + CHAR_LENGTH('1、'))
                    ),
                    '等'
                )
            ELSE s.f009
        END
    ) AS simple_content,
    p.TRADECODE,
    p.id,
    p.F002,
    s.F009,
    s.F013,
    DATE_FORMAT(s.declaredate, '%c月%e日') AS declaredate
FROM T_STK159 AS s
JOIN T_PUB010 AS p ON s.comcode = p.f006
WHERE
    p.F005 = 2 
    AND p.F004 IN (0, 1, 9) 
    AND p.STATE = '1' 
    AND p.F007 = '1' 
    AND s.F005 IS NOT NULL 
    AND s.declaredate >= DATE_SUB(NOW(), INTERVAL 480 HOUR)
ORDER BY s.declaredate DESC;

主要改动说明:

  1. 去除了 CONCAT(LEFT(:原写法既没有给 LEFT 提供长度参数,也无需嵌套 CONCAT(因为 CASE 内部已经 CONCAT 了“等”字)。
  2. 使用 RTRIM():去除尾部空格(常见于原始字段中多余的空格或换行符)。如果您想去掉最后一个字符(任意字符),请改用 LEFT(字符串, CHAR_LENGTH(字符串)-1),但通常用 RTRIM 更合理。
  3. 其他部分保持不变。

如果您确实需要去掉最后一个字符(例如去掉结尾的“和”或空格):

请替换 RTRIM(...) 为:

LEFT(
    CASE ... END,
    CHAR_LENGTH(CASE ... END) - 1
) AS simple_content

但请注意:如果原字符串为空或只有一个字符,会导致长度负数错误,需要加保护。建议优先使用 RTRIMTRIM

执行修改后的 SQL 应能正常运行。

👤 用户:

SELECT s.comcode, CASE WHEN CHARLENGTH(CAST(s.F005 AS CHAR)) > 9 THEN CONCAT(FORMAT(s.F005 / 100000000, 2), '亿元') WHEN CHARLENGTH(CAST(s.F005 AS CHAR)) >= 5 THEN CONCAT(FORMAT(s.F005 / 10000, 2), '万元') ELSE CONCAT(FORMAT(s.F005, 2), '元') END AS F005, -- 修复:去掉错误的 LEFT/CONCAT 嵌套,直接使用 CASE 结果,并用 RTRIM 去除尾部空格 RTRIM( CASE WHEN LOCATE('1、', s.f009) > 0 AND LOCATE('2、', s.f009) > 0 THEN CONCAT( SUBSTRING( f009, LOCATE('1、', s.f009) + CHARLENGTH('1、'), LOCATE('2、', s.f009) - (LOCATE('1、', s.f009) + CHARLENGTH('1、')) ), '等' ) ELSE s.f009 END ) AS simplecontent, p.TRADECODE, p.id, p.F002, s.F009, s.F013, DATEFORMAT(s.declaredate, '%c月%e日') AS declaredate FROM TSTK159 AS s JOIN TPUB010 AS p ON s.comcode = p.f006 WHERE p.F005 = 2 AND p.F004 IN (0, 1, 9) AND p.STATE = '1' AND p.F007 = '1' AND s.F005 IS NOT NULL AND s.declaredate >= DATE_SUB(NOW(), INTERVAL 480 HOUR) ORDER BY s.declaredate DESC

1052 - Column 'f009' in field list is ambiguous

时间: 0.002s


💭 思考过程

我们注意到错误信息:Column 'f009' in field list is ambiguous。这是在查询的 SELECT 列表中,s.F009 出现了两次(一次在 simplecontent 内部的 CASE 中引用了 f009 而未加表别名,另一次在最后显式写了 s.F009)。但在 SUBSTRINGLOCATE 中,f009 没有指定表别名,而 TSTK159TPUB010 都有该列吗?错误提示说 ambiguous,意味着 f009 在两个表中都存在。检查:TSTK159f009TPUB010 也有 f009?可能 TPUB010 也有名为 f009 的列。我们需要在 simple_content 内部的 f009 前加上 s. 前缀。

修改:将所有 f009 引用改为 s.f009。同时注意 LOCATE('2、', s.f009) 等。另外最后显式地也写了 s.F009,没问题。

修改后的 SQL:

SELECT
    s.comcode,
    CASE
        WHEN CHAR_LENGTH(CAST(s.F005 AS CHAR)) > 9 THEN CONCAT(FORMAT(s.F005 / 100000000, 2), '亿元')
        WHEN CHAR_LENGTH(CAST(s.F005 AS CHAR)) >= 5 THEN CONCAT(FORMAT(s.F005 / 10000, 2), '万元')
        ELSE CONCAT(FORMAT(s.F005, 2), '元')
    END AS F005,
    RTRIM(
        CASE 
            WHEN LOCATE('1、', s.f009) > 0 AND LOCATE('2、', s.f009) > 0 THEN
                CONCAT(
                    SUBSTRING(
                        s.f009,
                        LOCATE('1、', s.f009) + CHAR_LENGTH('1、'),
                        LOCATE('2、', s.f009) - (LOCATE('1、', s.f009) + CHAR_LENGTH('1、'))
                    ),
                    '等'
                )
            ELSE s.f009
        END
    ) AS simple_content,
    p.TRADECODE,
    p.id,
    p.F002,
    s.F009,
    s.F013,
    DATE_FORMAT(s.declaredate, '%c月%e日') AS declaredate
FROM T_STK159 AS s
JOIN T_PUB010 AS p ON s.comcode = p.f006
WHERE
    p.F005 = 2 
    AND p.F004 IN (0, 1, 9) 
    AND p.STATE = '1' 
    AND p.F007 = '1' 
    AND s.F005 IS NOT NULL 
    AND s.declaredate >= DATE_SUB(NOW(), INTERVAL 480 HOUR)
ORDER BY s.declaredate DESC;

注意:simple_content 中使用了 RTRIM 去除尾部空格。如果用户意图是“截取最后一位”,可能是因为原始字段末尾有不可见字符。使用 RTRIM 通常可以处理空格。但如果要严格去掉最后一个字符(不论是什么),需要改用 LEFT 并计算长度减一,但可能会因为空字符串出错。目前先按 RTRIM 提供。

您的 SQL 出现错误 1052 - Column 'f009' is ambiguous,因为 TSTK159TPUB010 两张表中都含有 f009 列,而您在 CASE 表达式内部直接写了 f009 没有加表别名。需要将所有 f009 明确指定为 s.f009

以下是修正后的 SQL:

SELECT
    s.comcode,
    CASE
        WHEN CHAR_LENGTH(CAST(s.F005 AS CHAR)) > 9 THEN CONCAT(FORMAT(s.F005 / 100000000, 2), '亿元')
        WHEN CHAR_LENGTH(CAST(s.F005 AS CHAR)) >= 5 THEN CONCAT(FORMAT(s.F005 / 10000, 2), '万元')
        ELSE CONCAT(FORMAT(s.F005, 2), '元')
    END AS F005,
    RTRIM(
        CASE 
            WHEN LOCATE('1、', s.f009) > 0 AND LOCATE('2、', s.f009) > 0 THEN
                CONCAT(
                    SUBSTRING(
                        s.f009,
                        LOCATE('1、', s.f009) + CHAR_LENGTH('1、'),
                        LOCATE('2、', s.f009) - (LOCATE('1、', s.f009) + CHAR_LENGTH('1、'))
                    ),
                    '等'
                )
            ELSE s.f009
        END
    ) AS simple_content,
    p.TRADECODE,
    p.id,
    p.F002,
    s.F009,
    s.F013,
    DATE_FORMAT(s.declaredate, '%c月%e日') AS declaredate
FROM T_STK159 AS s
JOIN T_PUB010 AS p ON s.comcode = p.f006
WHERE
    p.F005 = 2 
    AND p.F004 IN (0, 1, 9) 
    AND p.STATE = '1' 
    AND p.F007 = '1' 
    AND s.F005 IS NOT NULL 
    AND s.declaredate >= DATE_SUB(NOW(), INTERVAL 480 HOUR)
ORDER BY s.declaredate DESC;

修改说明:

  • SUBSTRING(f009, ... 改为 SUBSTRING(s.f009, ...
  • LOCATE('1、', f009) 改为 LOCATE('1、', s.f009)
  • LOCATE('2、', f009) 改为 LOCATE('2、', s.f009)
  • ELSE s.f009 已经正确

这样就不会再有歧义错误了。同时保留了 RTRIM 去除尾部空格,如果您的原始意图是“截取最后一位”来解决空格问题,RTRIM 是最合适的方法。如果您确实需要去掉任意最后一个字符(比如某些不可见字符),请告知,我可以调整为 LEFT(...) 方式并增加长度保护。