MySQL如何正确查询处于指定版本范围内的版本值?
MySQL中x.y.z格式版本号的正确范围查询方案
原查询的问题根源
你当前的查询直接用字符串类型的版本号做BETWEEN比较,会因为字符串逐字符对比的特性导致逻辑错误。比如字符串'2.2.100'会被判定为小于'2.2.2'——因为第三个段的第一个字符'1'的ASCII值小于'2',完全不符合版本号的实际大小逻辑。
最优解决方案:使用VERSION_COMPARE()函数
MySQL内置的VERSION_COMPARE(v1, v2)函数专门用于处理版本号字符串的比较,返回值规则:
- 若
v1 > v2,返回1 - 若
v1 = v2,返回0 - 若
v1 < v2,返回-1
利用这个函数可以写出逻辑正确且可读性强的查询:
SET @v = '2.2.2'; SELECT version FROM app_versions AS V WHERE VERSION_COMPARE(@v, V.min_ver) >= 0 AND VERSION_COMPARE(@v, V.max_ver) <= 0;
针对你的测试用例:
- 当
@v='2.2.2'时,会匹配1.10.1 -> 2.3.3的区间(因为2.2.2在1.10.1和2.3.3之间) - 不会匹配
2.2.100 -> 2.2.111的区间(因为2.2.2 < 2.2.100)
备选方案:拆分版本号为数值段对比
如果需要自定义版本比较规则(比如某些场景下版本段的权重不同),可以通过SUBSTRING_INDEX拆分版本号的主、次、修订号,转换为整数后逐段比较:
SET @v = '2.2.2'; -- 拆分目标版本为数值段 SET @major_v = CAST(SUBSTRING_INDEX(@v, '.', 1) AS UNSIGNED); SET @minor_v = CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(@v, '.', 2), '.', -1) AS UNSIGNED); SET @patch_v = CAST(SUBSTRING_INDEX(@v, '.', -1) AS UNSIGNED); SELECT version FROM app_versions AS V WHERE -- 拆分min_ver的数值段并对比 CAST(SUBSTRING_INDEX(V.min_ver, '.', 1) AS UNSIGNED) < @major_v OR ( CAST(SUBSTRING_INDEX(V.min_ver, '.', 1) AS UNSIGNED) = @major_v AND CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(V.min_ver, '.', 2), '.', -1) AS UNSIGNED) < @minor_v ) OR ( CAST(SUBSTRING_INDEX(V.min_ver, '.', 1) AS UNSIGNED) = @major_v AND CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(V.min_ver, '.', 2), '.', -1) AS UNSIGNED) = @minor_v AND CAST(SUBSTRING_INDEX(V.min_ver, '.', -1) AS UNSIGNED) <= @patch_v ) -- 拆分max_ver的数值段并对比 AND ( CAST(SUBSTRING_INDEX(V.max_ver, '.', 1) AS UNSIGNED) > @major_v OR ( CAST(SUBSTRING_INDEX(V.max_ver, '.', 1) AS UNSIGNED) = @major_v AND CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(V.max_ver, '.', 2), '.', -1) AS UNSIGNED) > @minor_v ) OR ( CAST(SUBSTRING_INDEX(V.max_ver, '.', 1) AS UNSIGNED) = @major_v AND CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(V.max_ver, '.', 2), '.', -1) AS UNSIGNED) = @minor_v AND CAST(SUBSTRING_INDEX(V.max_ver, '.', -1) AS UNSIGNED) >= @patch_v ) );
这种方案灵活性更高,但代码量更大,适合特殊业务场景。
内容的提问来源于stack exchange,提问作者Tu Le Anh
相关产品推荐
相关产品推荐

