使用SELECT MAX获取23-XXX格式采购订单号下一号的问题排查
问题原因
采购订单号是字符串类型,MAX()函数按字符串字典序排序而非数值大小排序。比如字符串"23-1000"与"23-999"比较时,因'1'的ASCII码小于'9',"23-1000"会被判定为更小,导致MAX()返回"23-999";当订单号到"23-9999"和"23-10000"时,同样逻辑会让MAX()返回"23-9999",重复出现错误。
解决方案
1. 最优方案:拆分字段存储
修改数据表结构,将订单号拆分为两个独立字段:
Year_Part(int类型,存储"23"这类年份前缀)Sequence_Number(int类型,存储"999"这类序号)
生成新订单号时,直接取对应年份下的MAX(Sequence_Number) + 1,再拼接成"23-1000"格式。这种方式从根源避免字符串排序问题,同时便于后续统计和维护。
2. 不改表结构的临时解决办法
在SQL中手动拆分订单号,将序号部分转为数值类型后再取最大值,示例SQL:
SELECT CONCAT( LEFT(Purchase_Order_Number, CHARINDEX('-', Purchase_Order_Number)), MAX(CAST(SUBSTRING(Purchase_Order_Number, CHARINDEX('-', Purchase_Order_Number) + 1, LEN(Purchase_Order_Number)) AS INT)) + 1 ) AS Next_Purchase_Order_Number FROM dbo.Purchase_Order WHERE Purchase_Order_Number LIKE '__-%' -- 过滤格式合法的订单号
该SQL先提取订单号前缀(比如"23-"),再把后面的序号转为整数取最大值加1,最后拼接成新订单号,不管序号是3位、4位还是更多位,都能正确获取下一个序号。
3. 并发场景补充
如果存在多用户同时生成订单号的情况,建议使用数据库事务+排他锁,或者利用SQL Server的SEQUENCE对象生成唯一序号,避免出现重复订单号的问题。
内容的提问来源于stack exchange,提问作者Dave Hampel
相关产品推荐
相关产品推荐

