Мы создаем успех.

Строковые функции ASCII() и ORD() в MySql. Выборка по алфавиту.

Главная » Блог » Строковые функции ASCII() и ORD() в MySql. Выборка по алфавиту.

Наша компания на данный момент занимается разработкой игрового портала, с каталогом игр, в котором есть около 5000 игр. В техническом задании указано использовать выборку по алфавиту, базу данных MySql.

В этой статье я хотел осветить некоторые моменты подобных MySql запросов. Для тестирования возможностей нам понадобится таблица, где мы создадим одно поле `name`, которое должно быть обязательно индексом, так как по этому полю мы будем производить выборки.

CREATE TABLE IF NOT EXISTS `engine_game` (
  `name` varchar(300) COLLATE utf8_unicode_ci NOT NULL,
  KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Заполним это поле разными данными, чтобы можно было протестировать.

ASCII() возвращает нам ASCII-код крайнего слева символа. Функция ORD() также возвращает ASCII-код крайнего слева символа, но при условии что символ не является многобайтным. Если он таковым является, то код рассчитывается по формуле, которую вы можете посмотреть в официальной документации.

Итак, давайте на примерах сравним их, но прежде сделаем в консоли:

mysql> SET NAMES utf8;

У меня кодировка базы UTF8. Если ваша кодировка другая, подставьте ее туда.

mysql> SELECT `name`, ASCII(`name`) as ascii_name, ord(`name`) as ord_name FROM `engine_game`;
+---------------------------------+------------+----------+
| name                            | ascii_name | ord_name |
+---------------------------------+------------+----------+
| Einherjar: The Viking's Blood   |         69 |       69 |
| Joyous Rebel                    |         74 |       74 |
| Joyous Rebel 2                  |         74 |       74 |
| 7.62                            |         55 |       55 |
| A Game of Dwarves: Star Dwarves |         65 |       65 |
+---------------------------------+------------+----------+
5 rows in set (0.00 sec)

Как видим, обе функции возвращают нам одинаковые значения. Давайте теперь попробуем то же самое с русским текстом.

mysql> SELECT `name`, ASCII(`name`) as ascii_name, ord(`name`) as ord_name FROM `engine_game`;
+----------------------------------------------------------+------------+----------+
| name                                                     | ascii_name | ord_name |
+----------------------------------------------------------+------------+----------+
| Горький-18: Мужская работа для PC                        |        208 |    53395 |
| За гранью: Две души                                      |        208 |    53399 |
+----------------------------------------------------------+------------+----------+
2 rows in set (0.00 sec)

Значения изменились! Более того, ASCII функция возвращает на любую букву русского алфавита диапазон кодов от 208 до 209, когда работа идет в UTF8! Следовательно использование функции ASCII() в нашем случае отпадает!

Попробуем теперь сделать выборку через функцию ORD().

mysql> SELECT `name` FROM `engine_game` WHERE ORD(`name`) = ORD('З');
+------------------------------------+
| name                               |
+------------------------------------+
| За гранью: Две души                |
+------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT `name` FROM `engine_game` WHERE ORD(`name`) = ORD('з');
+-------------------+
| name              |
+-------------------+
| за гранью         |
+-------------------+
1 row in set (0.00 sec)

Из этого примера видно, что данная функция чувствительна к регистру, и для того, чтобы ее использовать для выборки, придется использовать 2 раза.

mysql> SELECT `name` FROM `engine_test` WHERE ORD(`name`) = ORD('з') OR ORD(`name`) = ORD('З');
+------------------------------------+
| name                               |
+------------------------------------+
| за гранью                          |
| За гранью: Две души                |
+------------------------------------+
2 rows in set (0.00 sec)

Из этого можно сделать вывод, что использование данной функции для выборки по алфавиту — не самое рациональное решение. Зато ее можно использовать для выборки от 0 до 9:

mysql> SELECT `name` FROM `engine_test` WHERE ORD(`name`) >= ORD('0') AND ORD(`name`) <= ORD('9');
+------+
| name |
+------+
| 0    |
| 1    |
| 2    |
| 3    |
| 4    |
| 5    |
| 6    |
| 7    |
| 8    |
| 9    |
+------+
10 rows in set (0.00 sec)

В следующей статье я рассмотрю функцию LEFT(), выражение вида "LIKE '{string}%'".