Mysql查询琐事

时间:2012-10-19 19:30:40

标签: mysql sql database

更新:请假设,我的版本号x.x.x.x中只有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 :(如果没有可能的解决方案,那么我可以将数据类型更改为其他,但这仍然无法解决问题。

6 个答案:

答案 0 :(得分:5)

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

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

SQL-Fiddle

中进行测试

答案 1 :(得分:1)

当您尝试获取max:
时,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(VERSION AS SIGNED);
1
1
1
1

这真的有道理。你想如何猜测MySQL,你想要什么? MySQL应该用于存储数据,你应该自己格式化。

一个好的解决方案是使用多个字段用于版本:
id int,os varchar, versionMajor int,versionMinor int,versionMoreMinor int,versionEvenMoreMinor int

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

答案 2 :(得分: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

答案 3 :(得分: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, '');

Source

此外,你可能想要考虑到这种痛苦的原因是因为你基本上违反了第一种正常形式。您指定的表单的版本号实际上是四个不同的值:主要版本,次要版本,修订版本(或维护版本)和构建版本。您的表结构应使用相同的格式:

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更改为varchar,并根据我的经验覆盖90%的案例

答案 4 :(得分:0)

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

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

<强> UPD

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

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`
抱歉,代码改进了

答案 5 :(得分: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