Регистрозависимая уникальность и регистронезависимый поиск - PullRequest
9 голосов
/ 02 января 2012

У меня есть таблица с полем с использованием кодировки utf8 и параметров сортировки utf8_unicode_ci:

CREATE TABLE dictionary (
    a varchar(128) NOT NULL
) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Сопоставление utf8_unicode_ci требуется для эффективного нечувствительного к регистру поиска с расширениями и лигациями. Для этого у меня есть индекс:

CREATE INDEX a_idx on dictionary(a);

Проблема: Кроме того, я должен убедиться, что все сохраненные значения поля a уникальны, но чувствительны к регистру . Немецкий пример: «blühen» и «Blühen» должны храниться в таблице. Но добавление «Blühen» во второй раз не должно быть возможным.

Есть ли встроенная функциональность в MySQL, чтобы иметь оба?

К сожалению, кажется, что невозможно установить параметры сортировки для индекса в MySQL 5.1.

Решения этой проблемы включают проверку уникальности перед вставкой или триггер. И то, и другое гораздо менее элегантно, чем использование уникального индекса.

Ответы [ 3 ]

4 голосов
/ 02 января 2012

Ну, есть 2 способа сделать это:

  1. с использованием _bin collation
  2. изменить тип данных на VARBINARY

Случай 1: использование _bin collation

Создайте свою таблицу следующим образом:

CREATE TABLE `dictionary` (
 `a` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
 UNIQUE KEY `idx_un_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Обратите внимание:

  1. тип данных столбца a
  2. УНИКАЛЬНЫЙ указатель на столбец a

Случай 2: использование VARBINARY типа данных

Создайте свою таблицу следующим образом:

CREATE TABLE `dictionary` (
 `a` VARBINARY(128) NOT NULL,
 UNIQUE KEY `idx_uniq_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Обратите внимание:

  1. новый тип данных VARBINARY
  2. УНИКАЛЬНЫЙ указатель по столбцу a

Итак, оба вышеперечисленных решения вашей цели. Таким образом, они оба позволят значения, такие как 'abc', 'Abc', 'ABC', 'aBc' и т. Д., Но не разрешат одно и то же значение снова, если регистр совпадает.

Обратите внимание, что задание параметров сортировки "_bin" отличается от использования двоичного типа данных. Поэтому, пожалуйста, не стесняйтесь ссылаться на следующие ссылки:

  1. Двоичные и варварские типы данных
  2. _bin и двоичные параметры сортировки

Надеюсь, вышеизложенное поможет!

1 голос
/ 21 августа 2014

Этого можно добиться, добавив дополнительный столбец column_lower.

CREATE TABLE `dictionary` (
  `a` VARCHAR(128) NOT NULL,
  `a_lower` VARCHAR(128) NOT NULL,
  UNIQUE KEY `idx_un_a_lower` (`a_lower`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

Вставка, которая выглядит следующим образом:

insert into dictionary set a = x, a_lower = lower(x);

Выбор теперь может быть без учета регистра:

select * from dictionary where a_lower like lower('search_term%')

Обратите внимание, что столбец с индексом может содержать до 191 символа. Максимальный индекс MySQL может составлять 767 байт, то есть 767/4 (юникод может занимать до 4 байт, если вы используете сортировку utf8mb4) = 191,75 = 191 символ Если вы используете сортировку utf8, занимающую не более 3 байтов на символьный столбец, можно хранить не более 767/3 = 255 символов.

0 голосов
/ 31 декабря 2015
SELECT * FROM dictionary WHERE a COLLATE utf8_general_ci = 'abc'

Попробуйте это. Это сработает .. у меня сработало.

...