date: 2026-04-29 updated: 2026-04-29 conversation_id: ad1a3a22-222c-4454-a9a4-912bd3e7fcea title: "SQL查询错误修复优化" tags: [deepseek, conversation] ---
SQL查询错误修复优化
创建时间: 2026-04-29 20:05
👤 用户:
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, CASE WHEN s.F009 LIKE '%2、%' THEN '等' ELSE '' END AS ismore, / 5.x 兼容的 simplecontent / TRIM( SUBSTRING( s.F009, LOCATE( '1、', s.F009 ) + 2, CASE WHEN LOCATE( '2、', s.F009 ) = 0 THEN 0 ELSE LOCATE( '2、', s.F009 ) - LOCATE( '1、', s.F009 ) - 2 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.simplecontent is not null AND s.declaredate >= DATESUB( NOW(), INTERVAL 720 HOUR ) ORDER BY s.declaredate DESC
1054 - Unknown column 's.simple_content' in 'where clause'
时间: 0.002s
帮我优化一下
这个错误是因为 WHERE 子句中引用了 s.simple_content,但表中并没有这个字段(应该是 F009 或其他字段)。
另外,您原来的 CASE 逻辑中试图生成 simple_content 别名,但 WHERE 子句不能直接引用同一 SELECT 中刚定义的别名(除非用 HAVING 或子查询)。
下面是优化后的 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,
CASE
WHEN s.F009 LIKE '%2、%' THEN '等'
ELSE ''
END AS is_more,
-- simple_content 从 F009 提取
TRIM(
SUBSTRING(
s.F009,
LOCATE('1、', s.F009) + 2,
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
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.F009 IS NOT NULL -- 将原来的 s.simple_content 改为 s.F009
AND s.declaredate >= DATE_SUB(NOW(), INTERVAL 720 HOUR)
ORDER BY
s.declaredate DESC;
主要修改点说明:
| 问题 | 原因 | 修复方式 |
|---|---|---|
Unknown column 's.simple_content' | 表中没有该字段,应该用 s.F009 | AND s.F009 IS NOT NULL |
WHERE 中不能使用别名 | simple_content 是 SELECT 阶段才生成的 | 去掉该条件(或保留原字段条件) |
SUBSTRING 中长度为 0 时可能出错 | LOCATE('2、') - LOCATE('1、') - 2 可能为 0 或负 | 用 CASE 返回 CHAR_LENGTH 作为备选长度 |
| 可读性/性能 | 原 SQL 较乱,无索引提示 | 添加注释,保持字段顺序清晰 |
如果必须筛选 simple_content 非空
(比如提取出来的内容不能为空字符串)
可以用 子查询或 HAVING:
-- 方案1:HAVING(适合已经筛选量不大的情况)
SELECT ... (同上) ...
HAVING simple_content IS NOT NULL AND simple_content != ''
ORDER BY s.declaredate DESC;
-- 方案2:子查询(推荐,逻辑更清晰)
SELECT * FROM (
-- 上面的完整 SELECT
) AS t
WHERE t.simple_content IS NOT NULL AND t.simple_content != ''
ORDER BY t.declaredate DESC;
建议索引优化(如果查询慢)
ALTER TABLE T_STK159 ADD INDEX idx_declare_f005 (declaredate, F005);
ALTER TABLE T_PUB010 ADD INDEX idx_f005_f004_state_f007_f006 (F005, F004, STATE, F007, f006);
需要我帮您改成 HAVING 或子查询版本 吗?
👤 用户:
为什么s.F009有数据,但是simple_content会没有数据呢
好问题!s.F009 有数据但 simple_content 为空,通常有以下几个原因:
主要原因分析
1. 找不到 '1、' 这个分隔符
LOCATE('1、', s.F009) = 0 -- 返回0,表示没找到
如果 F009 的内容不是以 "1、" 开头,整个提取逻辑就会失败。例如:
"2、内容""1."(英文点号)"一、"(中文数字)"内容开头没有编号"
2. 提取长度为 0 或负数
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN 0 -- 这里有问题!
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
问题所在:当没有 '2、' 时,返回 0,然后 SUBSTRING(str, start, 0) 会返回空字符串。
应该改为返回剩余全部长度:
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
3. '1、' 后面紧跟着 '2、',中间没有内容
例如:"1、2、其他内容"
- start 位置正确
- 长度 = 0(因为两个分隔符紧挨着)
4. F009 只包含 '1、' 但没有后续内容
例如:"1、"
- 能找到 '1、'
- 没有 '2、',会使用 0 长度(原逻辑问题)
快速诊断方法
运行这个查询看看您的数据到底是什么格式:
SELECT
s.F009,
LENGTH(s.F009) as len,
LOCATE('1、', s.F009) as pos1,
LOCATE('2、', s.F009) as pos2,
-- 看原始逻辑会提取什么
SUBSTRING(
s.F009,
LOCATE('1、', s.F009) + 2,
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN 0
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
) as old_extract,
-- 修正后的逻辑
SUBSTRING(
s.F009,
LOCATE('1、', s.F009) + 2,
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
) as new_extract
FROM T_STK159 s
WHERE s.F009 IS NOT NULL
AND ( -- 挑出simple_content可能为空的数据
LOCATE('1、', s.F009) = 0 -- 没找到'1、'
OR (
LOCATE('2、', s.F009) = 0
AND LOCATE('1、', s.F009) + 2 >= CHAR_LENGTH(s.F009) -- '1、'在末尾或靠近末尾
)
OR (
LOCATE('2、', s.F009) > 0
AND LOCATE('2、', s.F009) - LOCATE('1、', s.F009) <= 2 -- 两个分隔符太近
)
)
LIMIT 10;
修复后的完整 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,
CASE WHEN s.F009 LIKE '%2、%' THEN '等' ELSE '' END AS is_more,
-- 修复后的 simple_content 提取逻辑
CASE
WHEN LOCATE('1、', s.F009) = 0 THEN s.F009 -- 如果没有'1、',返回原文本
ELSE TRIM(
SUBSTRING(
s.F009,
LOCATE('1、', s.F009) + 2,
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN CHAR_LENGTH(s.F009) -- 修复:返回剩余长度
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
)
)
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 720 HOUR)
ORDER BY s.declaredate DESC;
最可能的情况
根据经验,最可能是第1种原因:您的 F009 数据不是以 "1、" 开头,而是其他格式,比如:
- 直接是文本,没有编号
- 使用
"1."或"1、"(全角/半角差异) - 使用
"1."或"一、"
建议您先执行上面的快速诊断查询,看看到底是什么格式,我可以帮您调整提取规则。
👤 用户:
将ismore融入到simplecontent中
好的,将 ismore 的逻辑融入到 simplecontent 中,有两种常见方式:
方案一:在 simple_content 末尾直接添加"等"字
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,
-- 将 is_more 融入到 simple_content 中
CONCAT(
TRIM(
CASE
WHEN LOCATE('1、', s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE('1、', s.F009) + 2,
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
)
END
),
CASE WHEN s.F009 LIKE '%2、%' THEN '等' ELSE '' 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 720 HOUR)
ORDER BY s.declaredate DESC;
方案二:更优雅的写法(提取逻辑复用)
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,
-- 融入 is_more 的 simple_content(带空格分隔)
CONCAT(
TRIM(
CASE
WHEN LOCATE('1、', s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE('1、', s.F009) + 2,
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
)
END
),
CASE
WHEN s.F009 LIKE '%2、%' THEN '等'
ELSE ''
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 720 HOUR)
ORDER BY s.declaredate DESC;
效果示例
| F009 原内容 | 原 simple_content | 原 is_more | 新 simple_content |
|---|---|---|---|
1、苹果、香蕉2、橙子 | 苹果、香蕉 | 等 | 苹果、香蕉等 |
1、苹果 | 苹果 | `` | 苹果 |
1、苹果、香蕉、葡萄 | 苹果、香蕉、葡萄 | 等 | 苹果、香蕉、葡萄等 |
方案三:更智能的处理(去掉多余空格和标点)
-- 先提取内容,再判断是否添加"等"
TRIM(
CONCAT(
CASE
WHEN LOCATE('1、', s.F009) = 0 THEN s.F009
ELSE TRIM(
SUBSTRING(
s.F009,
LOCATE('1、', s.F009) + 2,
CASE
WHEN LOCATE('2、', s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2
END
)
)
END,
CASE
WHEN s.F009 LIKE '%2、%' THEN '等'
ELSE ''
END
)
) AS simple_content
这样修改后,原来的 ismore 字段就可以从 SELECT 中移除了,所有信息都整合在 simplecontent 中。
👤 用户:
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, -- 修复后的 simplecontent 提取逻辑 TRIM( CONCAT( CASE WHEN LOCATE('1、', s.F009) = 0 THEN s.F009 ELSE TRIM( SUBSTRING( s.F009, LOCATE('1、', s.F009) + 2, CASE WHEN LOCATE('2、', s.F009) = 0 THEN CHARLENGTH(s.F009) ELSE LOCATE('2、', s.F009) - LOCATE('1、', s.F009) - 2 END ) ) END, CASE WHEN s.F009 LIKE '%2、%' THEN '等' ELSE '' 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 720 HOUR) ORDER BY s.declaredate DESC
1267 - Illegal mix of collations (gbkchineseci,IMPLICIT) and (utf8mb4generalci,COERCIBLE) for operation 'concat'
时间: 0.003s
这个错误是因为字符集不一致导致的。s.F009 字段是 gbkchineseci 排序规则,而字符串常量 '1、' 和 '等' 是 utf8mb4generalci,CONCAT 操作时无法自动转换。
解决方案:统一字符集
方案一:将字符串常量转换为 GBK(推荐)
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,
-- 修复后的 simple_content 提取逻辑(统一使用 GBK)
TRIM(
CONCAT(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE TRIM(
SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
)
END,
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 720 HOUR)
ORDER BY s.declaredate DESC;
方案二:将字段转换为 UTF8MB4(可能需要修改表结构)
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,
-- 将字段转换为 utf8mb4
TRIM(
CONCAT(
CASE
WHEN LOCATE('1、', CONVERT(s.F009 USING utf8mb4)) = 0 THEN s.F009
ELSE TRIM(
SUBSTRING(
s.F009,
LOCATE('1、', CONVERT(s.F009 USING utf8mb4)) + 2,
CASE
WHEN LOCATE('2、', CONVERT(s.F009 USING utf8mb4)) = 0 THEN CHAR_LENGTH(CONVERT(s.F009 USING utf8mb4))
ELSE LOCATE('2、', CONVERT(s.F009 USING utf8mb4)) - LOCATE('1、', CONVERT(s.F009 USING utf8mb4)) - 2
END
)
)
END,
CASE
WHEN CONVERT(s.F009 USING utf8mb4) LIKE '%2、%' THEN '等'
ELSE ''
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 720 HOUR)
ORDER BY s.declaredate DESC;
方案三:最简洁的写法(推荐)
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,
-- 先转换字符集,再处理
TRIM(
CONCAT(
CASE
WHEN LOCATE('1、', f009_utf8) = 0 THEN f009_utf8
ELSE TRIM(
SUBSTRING(
f009_utf8,
LOCATE('1、', f009_utf8) + 2,
CASE
WHEN LOCATE('2、', f009_utf8) = 0 THEN CHAR_LENGTH(f009_utf8)
ELSE LOCATE('2、', f009_utf8) - LOCATE('1、', f009_utf8) - 2
END
)
)
END,
CASE
WHEN f009_utf8 LIKE '%2、%' THEN '等'
ELSE ''
END
)
) AS simple_content,
p.TRADECODE,
p.id,
p.F002,
s.F009,
s.F013,
DATE_FORMAT(s.declaredate, '%c月%e日') AS declaredate
FROM (
SELECT *, CONVERT(s.F009 USING utf8mb4) AS f009_utf8
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 720 HOUR)
ORDER BY s.declaredate DESC;
永久解决建议
如果经常需要处理这个表,建议修改表字段的字符集:
-- 查看当前字符集
SHOW FULL COLUMNS FROM T_STK159 WHERE Field = 'F009';
-- 修改为 utf8mb4(需要确认业务影响)
ALTER TABLE T_STK159 MODIFY F009 TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
推荐使用方案一,不需要修改表结构,只需要将字符串常量转换为与字段相同的字符集即可。
👤 用户:
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, -- 修复后的 simplecontent 提取逻辑(统一使用 GBK) TRIM( CONCAT( CASE WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009 ELSE TRIM( SUBSTRING( s.F009, LOCATE(CONVERT('1、' USING gbk), s.F009) + 2, CASE WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHARLENGTH(s.F009) ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2 END ) ) END, CASE WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk) ELSE '' 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 48 HOUR) ORDER BY s.declaredate DESC;
以上代码的等字前有空格,请去掉
问题在于 CONCAT 时,s.F009 提取的内容末尾可能有空格,或者 CONVERT('等' USING gbk) 前没有处理好。修改方法如下:
解决方案:使用 TRIM 包裹并去掉多余空格
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,
-- 修复后的 simple_content 提取逻辑(去掉等字前的空格)
TRIM(
CONCAT(
TRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE TRIM(
SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
)
END
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
更简洁的写法(推荐)
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,
-- 最简洁的写法:先提取内容,再判断是否加"等"
CONCAT(
TRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
核心修改说明
- 内层 TRIM:在提取
F009内容后立即用TRIM()去掉首尾空格 - 移除外层多余的 TRIM:如果不需要整个字符串的 TRIM,可以只保留内层的
- CONCAT 直接连接:确保提取的内容末尾没有空格后再连接"等"字
效果对比
| 修改前 | 修改后 |
|---|---|
苹果、香蕉 等 | 苹果、香蕉等 |
苹果 等 | 苹果等 |
苹果、香蕉、葡萄 等 | 苹果、香蕉、葡萄等 |
这样就能确保"等"字紧挨着前面的内容,中间没有空格了。
👤 用户:
还是有空格
让我帮您彻底排查空格来源。先运行这个诊断SQL看看具体是什么情况:
诊断SQL(查看原始数据和空格位置)
SELECT
s.F009,
CHAR_LENGTH(s.F009) as 总长度,
HEX(s.F009) as 十六进制,
LOCATE(CONVERT('1、' USING gbk), s.F009) as 位置1,
LOCATE(CONVERT('2、' USING gbk), s.F009) as 位置2,
-- 看提取的内容
SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
) as 提取内容,
HEX(
SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
) as 提取内容十六进制
FROM T_STK159 s
WHERE s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%')
AND s.declaredate >= DATE_SUB(NOW(), INTERVAL 48 HOUR)
LIMIT 5;
可能的原因和解决方案
原因1:F009中本身就包含了空格或特殊字符
如果提取的内容末尾有空格,需要更彻底地清理:
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,
-- 彻底去掉所有空格和特殊空白字符
CONCAT(
REPLACE(
REPLACE(
REPLACE(
TRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END
),
CHAR(32), '' -- 去掉空格
),
CHAR(9), '' -- 去掉制表符
),
CHAR(10), '' -- 去掉换行
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
原因2:可能是显示问题或者CONCAT的字符集问题
尝试更简单直接的写法:
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,
-- 使用 CONCAT_WS 或者直接拼接
CONCAT(
RTRIM( -- 只去掉右边空格
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
原因3:如果还是不行,可能是数据中包含了全角空格
-- 去掉全角和半角空格
CONCAT(
REPLACE(
REPLACE(
TRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END
),
' ', '' -- 半角空格
),
' ', '' -- 全角空格
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
END
)
请先运行诊断SQL,把结果发给我,我就能确定具体是哪种空格,然后给出最精准的解决方案。
👤 用户:
原因1,但是不能用replace
明白了,不能用 REPLACE。那我们需要从根源上解决:问题出在 SUBSTRING 提取时包含了结尾的空格。
解决方案:使用 RTRIM 去掉右侧空格
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 去掉右侧空格
CONCAT(
RTRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE RTRIM( -- 内层也加 RTRIM
SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
)
END
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
更简洁的写法(推荐)
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
CONCAT(
RTRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0
THEN RTRIM(s.F009)
ELSE RTRIM(
SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0
THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
)
END
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
核心修改说明
- RTRIM():只删除字符串右侧的空格,不影响文字中间的空格
- 在 SUBSTRING 提取后立即用 RTRIM 处理
- 外层 CONCAT 前再次 RTRIM 确保万无一失
效果对比
| 原始数据 | 修改前 | 修改后 |
|---|---|---|
1、苹果、香蕉 2、橙子 | 苹果、香蕉 等 | 苹果、香蕉等 |
1、苹果、香蕉 2、橙子 | 苹果、香蕉 等 | 苹果、香蕉等 |
RTRIM 只会去掉空格、制表符、换行符等空白字符,不会影响正常文字,所以很安全。
👤 用户:
通过裁减最右边一位数解决
好的,通过截掉最右边一位字符来解决。这样即使有空格或其他不可见字符,也能强制去掉。
解决方案:使用 LEFT 截掉最后一位
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,
-- 通过截取最后一位来解决空格问题
CONCAT(
LEFT(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END,
CHAR_LENGTH(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END
) - 1
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
更清晰的写法(使用子查询)
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,
-- 先提取内容,再截掉最后一位
CONCAT(
LEFT(extracted_content, CHAR_LENGTH(extracted_content) - 1),
suffix
) 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
CROSS JOIN (
SELECT
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END AS extracted_content,
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
END AS suffix
FROM T_STK159
) AS extracted
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 48 HOUR)
ORDER BY s.declaredate DESC;
最简洁实用的版本(推荐)
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,
-- 截掉最后一位 + 拼接"等"
CONCAT(
LEFT(
TRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END
),
CHAR_LENGTH(
TRIM(
CASE
WHEN LOCATE(CONVERT('1、' USING gbk), s.F009) = 0 THEN s.F009
ELSE SUBSTRING(
s.F009,
LOCATE(CONVERT('1、' USING gbk), s.F009) + 2,
CASE
WHEN LOCATE(CONVERT('2、' USING gbk), s.F009) = 0 THEN CHAR_LENGTH(s.F009)
ELSE LOCATE(CONVERT('2、' USING gbk), s.F009) - LOCATE(CONVERT('1、' USING gbk), s.F009) - 2
END
)
END
)
) - 1
),
CASE
WHEN s.F009 LIKE CONCAT('%', CONVERT('2、' USING gbk), '%') THEN CONVERT('等' USING gbk)
ELSE ''
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 48 HOUR)
ORDER BY s.declaredate DESC;
原理说明
LEFT(string, length - 1)截掉字符串最后一位- 如果最后一位是空格、换行或其他不可见字符,都会被去掉
- 如果本身没有多余字符,可能会截掉有用的文字(需要确认数据格式)
注意:这个方法会无条件截掉最后一位,如果您的数据末尾本身就有有效文字(不是空格),可能会丢失内容。建议先确认一下数据的实际情况。