Как указать сортировку с PDO без SET NAMES?

Мы можем явно установить набор символов utf8 при инициализации PDO, просто добавьте « charset=utf8 » в строку dsn. Но как конкретно указывать сортировку, используемую в соединении MySQL при использовании PDO?

Я не хочу использовать дополнительный запрос для этого:

 SET NAMES utf8 COLLATE utf8_unicode_ci; 

Есть ли какой-либо способ, не прибегая к «SET NAMES»? Или, будет ли проблема, если я не укажу сортировку?

Вот два ответа.

Вы можете установить это в DSN или как MYSQL_ATTR_INIT_COMMAND (параметры подключения).

Думаю, DSN лучше.

 $connect = new PDO( "mysql:host=$host;dbname=$db;charset=utf8", $user, $pass, array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ) ); 

Если вы укажете UTF-8 вы работаете со значением по умолчанию для utf8_general_ci по utf8_general_ci , если ваша таблица или поле db не использует что-то другое.

Если вы хотите, чтобы весь сервер ответил на эту настройку по умолчанию, используйте директивы конфигурации:

 collation_server=utf8_unicode_ci character_set_server=utf8 

Поэтому вам не нужно указывать его при подключении каждый раз.

Сопоставления влияют на сортировку символов и устанавливаются в таблице и в полях в вашей базе данных. Эти параметры соблюдаются при запросе таблицы. Убедитесь, что они установлены. Используйте имена UTF-8 с настройкой сортировки в вашем db.


Ваш комментарий:

«Люди должны знать, что набор символов и сортировка – это две разные вещи».

Давайте дадим цитату из руководства MySQL для доказательства этого:

SET NAMES 'charset_name' эквивалентен этим трех операторам:

 SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; 

Установка character_set_connection в charset_name также неявно устанавливает collation_connection для collation_connection по умолчанию для charset_name.

Мой ответ: он работает неявно, если ваши таблицы не меняют это явно.


Вопрос от комментария:

Как убедиться, что я не испортил вещи, поскольку мои таблицы не являются стандартными настройками utf8_general_ci?

Пример: сортировка столбцов отменяет сопоставление таблиц

 CREATE TABLE t1 ( col1 CHAR(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci ) CHARACTER SET latin1 COLLATE latin1_bin; 

Если оба параметра CHARACTER SET X и COLLATE Y указаны в столбце, используются набор символов X и сортировка Y. Столбец имеет набор символов utf8 и colulation utf8_unicode_ci как указано в столбце таблицы, тогда как таблица находится в latin1 + latin1_bin.

Пример: в общей таблице используется сортировка

Если сортировка явно не указана в столбце / поле, то используется сортировка таблицы:

 CREATE TABLE t1 ( col1 CHAR(10) ) CHARACTER SET latin1 COLLATE latin1_bin; 

col1 имеет сортировку latin1_bin.

Если вы хотите, чтобы сортировка utf8_unicode_ci , установите ее в свои таблицы в целом или в столбцы / поля.

Вопрос: «Как указать сортировку с PDO без SET NAMES? .. как явно указывать сортировку, используемую при подключении MySQL при использовании PDO?»

Ответ. Вы просто не можете сделать это, не используя SET NAMES или что-то подобное. Использование PDO::MYSQL_ATTR_INIT_COMMAND в массиве $options из PDO constuctor является единственным способом явно установить сопоставление соединений непосредственно в вашем коде соединения с использованием PDO. В противном случае вы будете полагаться на нечто меньшее, чем явный синтаксис (который не является ответом на вопрос). Конечно, любой другой метод менее прямой.

Некоторые версии MySQL (5.1) имеют две, 3-байтные Unicode, uft8-сортировки (unicode и general). Просто использование utf8 в строке $ dsn не будет явно выбирать версию «unicode» или «общую» версию коллекций utf8. PDO не является читателем разума.

Поэтому строка параметров может выглядеть примерно так:

 $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PERSISTENT => true, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8' COLLATE 'utf8_unicode_ci'"]; 

или

 $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PERSISTENT => true, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8' COLLATE 'utf8_general_ci'"]; 

Более поздние версии MySQL имеют 4-байтовую реализацию unicode utf8. Здесь вы должны указать utf8mb4, а не uft8.

 $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PERSISTENT => true, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'"];