Hi Stano,
there was a response by Michael Stassen on the list about a year ago on
this problem, which I hope he doesn't mind if I repeat below.
/Johan
Version numbers?

  CREATE TABLE ss (version VARCHAR(13));
  INSERT INTO ss VALUES ('1'),('1.1'),('1.2.1.2'),('1.10.1'),('1.2'),
                        ('1.4.1'),('2.1'),('2.2.1.2'),('2.10.1'),('2.4.1');

If each part is no larger than 255, you can leverage INET_ATON() to do what you want (up to the 4th part). The trick is making each of these look like an IP first by using CONCAT to add '0.0.0' to make sure every row has at least 4 parts, then SUBSTRING_INDEX to pull out just the first 4 parts.

  SELECT version FROM ss
  ORDER BY INET_ATON(SUBSTRING_INDEX(CONCAT(version,'.0.0.0'),'.',4));

+---------+
| version |
+---------+
| 1       |
| 1.1     |
| 1.2     |
| 1.2.1.2 |
| 1.4.1   |
| 1.10.1  |
| 2.1     |
| 2.2.1.2 |
| 2.4.1   |
| 2.10.1  |
+---------+
10 rows in set (0.00 sec)

Now, I must point out that because we are sorting on a function of the column, rather than on the column itself, we cannot use an index on the column to help with the sort. In other words, the sorting will be relatively slow.

One solution would be to separate the parts into separate columns, each of which could then be an appropriately sized integer (TINYINT, perhaps). You could use 0 or NULL for the missing parts, as you see fit (NULLS preserve the output format you specified, e.g. 1.1, but complicate matching).

  CREATE TABLE ss2 (v1 TINYINT UNSIGNED, v2 TINYINT UNSIGNED,
                    v3 TINYINT UNSIGNED, v4 TINYINT UNSIGNED,
                    KEY version_idx (v1,v2,v3,v4));

  INSERT INTO ss2 VALUES (1,NULL,NULL,NULL),(1,1,NULL,NULL),(1,2,1,2),

(1,10,1,0),(1,2,0,0),(1,4,1,0),(2,1,0,0),(2,2,1,2),
                         (2,10,1,NULL),(2,4,1,NULL);

Glue the parts together with CONCAT_WS() when you select them, and sort by all 4 parts:

  SELECT CONCAT_WS('.',v1,v2,v3,v4) version FROM ss2 ORDER BY v1,v2,v3,v4;
+----------+
| version  |
+----------+
| 1        |
| 1.1      |
| 1.2.0.0  |
| 1.2.1.2  |
| 1.4.1.0  |
| 1.10.1.0 |
| 2.1.0.0  |
| 2.2.1.2  |
| 2.4.1    |
| 2.10.1   |
+----------+
10 rows in set (0.00 sec)

In this case, the multicolumn index on the 4 parts will be used to sort.

Another option would be to use INET_ATON() when storing the values.

  CREATE TABLE ss3 (v INT UNSIGNED, KEY version_idx (v));

In this case, you'd have to use 0 for missing parts.

  INSERT INTO ss3 VALUES (INET_ATON('1.0.0.0')), (INET_ATON('1.1.0.0')),
                         (INET_ATON('1.2.1.2')), (INET_ATON('1.10.1.0')),
                         (INET_ATON('1.2.0.0')), (INET_ATON('1.4.1.0')),
                         (INET_ATON('2.1.0.0')), (INET_ATON('2.2.1.2')),
                         (INET_ATON('2.10.1.0')),(INET_ATON('2.4.1.0'));

Use INET_NTOA() when selecting to display dotted numbers, but sort by the values already in the column.

  SELECT INET_NTOA(v) version FROM ss3 ORDER BY v;

+----------+
| version  |
+----------+
| 1.0.0.0  |
| 1.1.0.0  |
| 1.2.0.0  |
| 1.2.1.2  |
| 1.4.1.0  |
| 1.10.1.0 |
| 2.1.0.0  |
| 2.2.1.2  |
| 2.4.1.0  |
| 2.10.1.0 |
+----------+
10 rows in set (0.00 sec)

As with the second version, the index on v will be used for the sort.

Finally, starting with mysql 4.1.2, INET_ATON() will assume 0s for missing parts, so long as you have at least two parts. That is, 1.1 will automatically be treated as 1.1.0.0, 1.0 as 1.0.0.0, and 1.2.3 as 1.2.3.0 (but 1 will be treated as 0.0.0.1). With 4.1.2 then, the above could be simplified slightly.

Michael


Stano Paska wrote:
Hi,

in my table I have one varchar(20) column where I store version number.
Version looks like:
1.1.2
1.2.1
1.10.3
It is possible order this column in natural order (1.2 before 1.10)?

Stano.


-- 
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:    http://lists.mysql.com/[EMAIL PROTECTED]

Reply via email to