3

更新:请假设,我的版本号 xxxx 中正好有 4 个元素

Table xyz (id int, os varchar, version varchar)

id      os       version
1       mac      1.0.0.4
2       android  1.0.1.2
3       mac      1.0.0.14
4       mac      1.0.0.07

我想找到每个操作系统的最大版本号。

select max(version), os from xyz group by os

但是在上面的数据示例中,它返回 1.0.0.4 作为 mac 的最高版本,而不是返回 1.0.0.14。有什么办法可以解决上面的查询吗?我知道版本是 varchar :( 如果没有可能的解决方案,那么我可以将数据类型更改为其他,但这仍然不能解决问题。

4

6 回答 6

5

如果版本中的 4 部分都是数字且不大于 255,则可以使用该INET_ATON()功能,反之亦然INET_NTOA()

SELECT INET_NTOA(MAX(INET_ATON(version))), os 
FROM xyz 
GROUP BY os ;

SQL-Fiddle中测试

于 2012-10-19T21:14:11.053 回答
1

当您尝试获取最大值时,Mysql 对此字段使用文本排序:
SELECT version FROM test ORDER BY VERSION;
1.0.0.14
1.0.0.4
1.0.07
1.0.1.2.4

但即使您尝试将其转换为整数,您也会得到
SELECT version FROM test ORDER BY CAST( VERSIONAS SIGNED);
1
1
1
1

这确实是有道理的。你想让 MySQL 怎么猜,你想要什么?MySQL应该用来存储数据,你应该自己格式化。

一个好的解决方案是使用几个字段作为版本:
id int、os varchar、versionMajor int、versionMinor int、versionMoreMinor int、versionEvenMoreMinor int

您应该能够根据需要对它们进行排序和格式化。

于 2012-10-19T19:57:34.147 回答
1

它很丑陋,但它正在完成这项工作:

select t1.os,t1.version from xyz t1 where (t1.os,
       ((cast(SUBSTRING_INDEX(t1.version, '.', 1) as unsigned)+1)*1000
       +(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t1.version, '.', -3), '.', 1) as unsigned)+1)*100
       +(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t1.version, '.', -2), '.', 1) as unsigned)+1)*10
       +(cast(SUBSTRING_INDEX(t1.version, '.', -1) as unsigned))+1))
  =(select t2.os,
   max((cast(SUBSTRING_INDEX(t2.version, '.', 1) as unsigned)+1)*1000
      +(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t2.version, '.', -3), '.', 1) as unsigned)+1)*100
      +(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t2.version, '.', -2), '.', 1) as unsigned)+1)*10
      +(cast(SUBSTRING_INDEX(t2.version, '.', -1) as unsigned))+1) 
from xyz t2 where t2.os=t1.os);

sqlfiddle

于 2012-10-19T20:55:27.693 回答
1

您在这里真正想做的是使用一个SPLIT函数,但这在 MySQL 中不可用。但是,您可以编写一个用户定义的函数来做同样的事情,或者将这个函数代码重构到一个视图中。

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, '');

来源

此外,您可能想考虑一下,之所以如此痛苦,是因为您实际上违反了第一范式。您指定形式的版本号实际上是四个不同的值:主要版本、次要版本、修订(或维护)和构建。您的表结构应使用相同的格式:

Table xyz (id int not null, os varchar not null, version_major int not null, version_minor int not null, version_revision int null, version_build int null)

然后,您只需使用一个ORDER BY子句对数据进行排序。您可以使用计算字段或视图来显示格式化的版本号。

现在,我知道您为什么选择使用单个字段了。版本号不一致,许多版本号不包括修订或构建值,其他包括字母等。但是,根据我的经验,您可以将其更改int为 avarchar并涵盖 90% 的情况。

于 2012-10-19T21:32:53.687 回答
0

您可以尝试将字符串转换为整数并获取 MAX()

SELECT MAX( CONVERT( REPLACE( `version`, '.', '' ), UNSIGNED ) ) from xyz

更新

还有另一种结束检测的方法,但它不适用于次要版本,也许您会调整这个繁重的查询以使其适合您

SELECT `version`,
    CONVERT(
        CONCAT_WS( '.',
            REPLACE( SUBSTRING( `version`, 1, ( CHAR_LENGTH( `version` ) - LOCATE( '.', REVERSE( `version` ) ) ) ), '.', '' ),
            SUBSTRING( `version`, 1 + LOCATE( '.', REVERSE( `version` ) ) * -1  )
        ),
        DECIMAL ( 10, 3 )
    )
    FROM `xyz`

抱歉,代码改进了

于 2012-10-19T19:36:28.173 回答
0

感谢@ntvf 的想法。这将做我正在寻找的。

select a.os, xyz.version from xyz, 
  (SELECT os, MAX( CONVERT(REPLACE(`version`,'.',''),UNSIGNED)) as version from xyz group by os) a 
where 
   a.os=xyz.os and 
   CONVERT(REPLACE( xyz.version, '.', '' ), UNSIGNED) = a.version
于 2012-10-19T21:09:46.117 回答