如何正确对WBS索引编码进行排序,解决ORDER BY排序错乱问题?
WBS层级编码正确排序方案
问题原因
wbs字段默认为字符串类型,字符串排序会按单个字符的ASCII值逐位比较,不会识别分段数值的实际大小,因此1.1.10会被判定为小于1.1.9,进而出现1.1.9之后直接跳转至1.2的排序错乱问题。
你当前使用的排序语句SELECT wbs FROM houses ORDER BY wbs为原生字符串排序逻辑,不支持层级编码的数值排序规则。
异常排序效果参考:
不同数据库环境解决方案
MySQL
通过SUBSTRING_INDEX拆分编码段后转数值排序,以下示例支持最多4级编码,层级更多可按规则扩展排序项:
SELECT wbs FROM houses ORDER BY CAST(SUBSTRING_INDEX(wbs, '.', 1) AS UNSIGNED), CASE WHEN LENGTH(wbs) - LENGTH(REPLACE(wbs, '.', '')) >= 1 THEN CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(wbs, '.', 2), '.', -1) AS UNSIGNED) ELSE 0 END, CASE WHEN LENGTH(wbs) - LENGTH(REPLACE(wbs, '.', '')) >= 2 THEN CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(wbs, '.', 3), '.', -1) AS UNSIGNED) ELSE 0 END, CASE WHEN LENGTH(wbs) - LENGTH(REPLACE(wbs, '.', '')) >= 3 THEN CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(wbs, '.', 4), '.', -1) AS UNSIGNED) ELSE 0 END;
PostgreSQL
直接使用string_to_array转数值数组排序,支持任意层级编码:
SELECT wbs FROM houses ORDER BY string_to_array(wbs, '.')::int[];
SQL Server(2016及以上版本)
使用PARSENAME拆分编码段后转数值排序,最多支持4级编码:
SELECT wbs FROM houses ORDER BY CAST(ISNULL(PARSENAME(REPLACE(wbs, '.', '.'), 4), '0') AS INT), CAST(ISNULL(PARSENAME(REPLACE(wbs, '.', '.'), 3), '0') AS INT), CAST(ISNULL(PARSENAME(REPLACE(wbs, '.', '.'), 2), '0') AS INT), CAST(ISNULL(PARSENAME(REPLACE(wbs, '.', '.'), 1), '0') AS INT);
长期优化方案
如果业务场景频繁需要按WBS编码排序,建议新增一个专用排序字段,存储补零后的标准化编码,例如将1.1.9转为0001.0001.0009、1.1.10转为0001.0001.0010,后续直接按该字段排序即可,查询性能远高于每次动态拆分计算。
内容的提问来源于stack exchange,提问作者Dan Padilla
相关产品推荐
相关产品推荐

