通过将简单排序规则添加到8位字符集来更改默认排序

时间:2012-06-14 15:40:09

标签: mysql sorting collation

之前发布过零回复的问题,所以我将基于此MySQL手册条目更新我的研究结果中的进一步澄清和详细信息。

过去,我使用了备用排序规则,允许我们指定备用默认排序。 Mysql允许将其降低到列级别,但我不理解某些以使其正常工作。

我们的客户在几乎所有对主表的引用中使用一组标准的一个字符代码,并且按照他们需要的顺序显示这些代码在PHP中使用函数和例程总是非常麻烦和困难。

SELECT * FROM myTable order by my_code

NORMAL, default sorting would return this:      DESIRED, default sorting should return this:
my_code | Description                           my_code | Description
 1      | Grade 1                               P  | Pre-Kindergarten
 2      | Grade 2                               K  | Kindergarten
 3      | Grade 3                               1  | Grade 1
 A      | Adult                                 2  | Grade 2
 K      | Kindergarten                          3  | Grade 3
 P      | Pre-Kindergarten                      A  | Adult

Docs at 10.4.3.中介绍了完成此操作的步骤,示例显示在Docs at 10.1.78中。

在步骤中,它显示了此表,以及如何指定权重。我想这就是我迷路的地方。我已经改变了如下所示的权重,将“P”(x50P)和“K”(x4B)放在“0”(x30)之前,但它完成的只是更改排序,以便“1”(x31)出现在“P”和“K”,所有其他排序似乎保持不变。

<collation name="latin1_test_ci">
<map>
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
50 4B 30 31 32 33 34 35 36 37 38 39 41 43 55 3A
3B 3C 3D 3E 3F 40 42 44 45 46 47 48 49 4A 4C 4D
4E 4F 51 52 53 54 56 57 58 59 5A 5B 5C 5D 5E 5F
60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
</map>
</collation>

使用上面的替代整理

对结果进行排序
Hex |my_code | Description
 32 |  2     |Grade 2
 33 |  3     |Grade 3
 41 |  A     |Adult Ed
 4B |  K     |Kindergarten
 31 |  1     |Grade 1
 50 |  P     |Pre-K

3 个答案:

答案 0 :(得分:2)

我意识到你说你想要改变整理,但这不需要ORDER BY,值得考虑。您可以将这些转换为ENUM类型,并按照它们在ENUM中的显示顺序进行排序。

CREATE TABLE myTable (
    my_code ENUM('P', 'K', '1', '2', '3', 'A'), 
    ...
)

强烈建议不要在ENUM中使用数字,因此您必须小心。主要问题是数字可以被视为ENUM中的索引或值。所以它的行为取决于它的类型,导致意想不到的结果。

答案 1 :(得分:2)

此表是权重表。如果你希望P i小于K,那么将00的权重加到P,将01的权重加到K.要设置一个权重,你应该在&#39;字母位置&#39;:为P位置50分配一个值。 P作为第一个字母:

<collation name="latin1_test_ci">
<map>
FF FF FF FF FF FF FF 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
00 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F   <-- first weight
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5C D7 5C 55 55 55 59 59 DE DF
41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5C F7 5C 55 55 55 59 59 DE FF
</map>
</collation>

编辑:添加测试和竞争表。

完整的表格应为:

<collation name="latin1_test_ci">
<map>
 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
 30 02 03 04 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 40 05 42 43 44 45 46 47 48 49 4A 01 4C 4D 4E 4F
 00 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
 44 4E 4F 4F 4F 4F 5C D7 5C 55 55 55 59 59 DE DF
 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
 44 4E 4F 4F 4F 4F 5C F7 5C 55 55 55 59 59 DE FF
</map>
</collation>

*测试:*

mysql> create table  b (a varchar(1) collate latin1_test_ci );

mysql> insert into b values
    -> ( 'P' ),
    -> ('K'),
    -> ('A'),
    -> ('1'),
    -> ('2'),
    -> ('3');


mysql> SHOW COLLATION LIKE 'latin1_test_ci';
+----------------+---------+----+---------+----------+---------+
| Collation      | Charset | Id | Default | Compiled | Sortlen |
+----------------+---------+----+---------+----------+---------+
| latin1_test_ci | latin1  | 56 |         |          |       0 |
+----------------+---------+----+---------+----------+---------+
1 row in set (0.00 sec)

mysql> select * from b order by a;
+------+
| a    |
+------+
| P    |
| K    |
| 1    |
| 2    |
| 3    |
| A    |
+------+
6 rows in set (0.00 sec)

答案 2 :(得分:1)

我认为你不需要自定义整理来实现目标。

订购结果集:

ORDER BY FIELD(my_code, 'P','K','1','2','3','4','5','6',
    '7','8','9','10','11','12','A')

限制结果集:

 WHERE my_code IN('K','1','2','3','4','5')

如果您要将这类功能写入大量查询,帮助函数可能是个好主意:

DELIMITER $$
CREATE FUNCTION `f_position`(in_char CHAR(1)) RETURNS INTEGER
BEGIN
    RETURN FIELD(in_char, 'P','K','1','2','3','4','5','6',
        '7','8','9','10','11','12','A');
END$$
DELIMITER ;

只需确保函数中引用了所有可能的代码,并按所需顺序放置。

使用这样的辅助函数,您可以编写如下查询:

WHERE f_position(grade) BETWEEN f_position('K') AND f_position('5')
ORDER BY f_position(grade)

使用辅助函数限制结果集(与WHERE grade IN(...)相反)的唯一缺点是函数调用会阻止使用“grade”列上的任何索引。