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.14 を返すのではなく、mac の最高バージョンとして 1.0.0.4 を返します。上記のクエリを修正する方法はありますか? バージョンが 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フィドルでテスト済み

于 2012-10-19T21:14:11.053 に答える
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, '');

ソース

さらに、これが非常に厄介な理由は、基本的に最初の正規形に違反しているためであると考える必要があります。指定するフォームのバージョン番号は、実際にはメジャー バージョン、マイナー バージョン、リビジョン (またはメンテナンス)、およびビルドの 4 つの異なる値です。テーブル構造は同じ形式を使用する必要があります。

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を aに変更してvarchar90% のケースをカバーできます。

于 2012-10-19T21:32:53.687 に答える
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 に答える
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 に答える