3

之前发布的问题是零响应,因此我将根据此 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

完成此操作的步骤在 10.4.3 的文档中进行了描述。, 示例在 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
4

3 回答 3

2

我知道您说过您想更改排序规则,但这不需要ORDER BY并且值得考虑。您可以将它们转换为ENUM类型,它们将按照它们在ENUM.

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

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

于 2012-07-15T17:39:51.973 回答
2

此表为权重表。如果您希望 P i 小于 K,则将 00 权重放在 P 上,将 01 权重放在 K 上。要放置权重,您应该在“字母位置”中指定一个值:对于 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)
于 2012-07-15T20:39:30.823 回答
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”上的任何索引。

于 2012-06-15T17:40:14.303 回答