2012-01-02 11 views
9

Tengo una tabla con un campo de un uso de la codificación UTF-8 y el cotejo utf8_unicode_ci:Caso singularidad sensible y búsqueda que ignore

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

Se requiere que el utf8_unicode_ci cotejo para una eficiente sensible a mayúsculas búsqueda con extensiones y ligaduras. Para este fin tengo el índice:

CREATE INDEX a_idx on dictionary(a); 

Problema: i Además debe asegurarse de que todos los valores almacenados del campo a son únicas, pero en un mayúsculas y minúsculas manera. Ejemplo en alemán: "blühen" y "Blühen" deben almacenarse en la tabla. Pero agregar "Blühen" por segunda vez no debería ser posible.

¿Existe una funcionalidad incorporada en MySQL para tener ambas?

Desafortunadamente, parece que no es posible establecer la intercalación para el índice en MySQL 5.1.

Las soluciones a este problema incluyen una comprobación de exclusividad antes de insertar o un desencadenador. Ambos son mucho menos elegantes que usar un índice único.

+0

Desafortunadamente, MySQL carece de características como índices/vistas materializadas o columnas calculadas o índices basados ​​en funciones que otros RDBMS tienen. Me interesaría ver cómo se hace, por supuesto ... – gbn

+0

¿Te vendría bien agregar otra columna con una intercalación de mayúsculas y minúsculas y una restricción uniquness? –

+0

Creo que este tema es una buena ayuda. http://stackoverflow.com/questions/4945349/mysql-search-with-uft8-general-ci-is-case-sensitive-for-fulltext – MahanGM

Respuesta

4

Bueno, hay 2 maneras de lograr esto:

  1. utilizando _bin cotejo
  2. cambio el tipo de datos a VARBINARY

Caso 1: utilizando _bin cotejo

Crear su tabla de la siguiente manera:

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; 

Tenga en cuenta:

  1. el tipo de datos de la columna a
  2. el índice único en la columna a

Caso 2: uso de VARBINARY dataype

Crea tu mesa de la siguiente manera:

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

Tenga en cuenta:

  1. el nuevo tipo de datos VARBINARY
  2. el índice único en la columna a

Así, tanto el anterior va a resolver su propósito. Es decir, ambos permitirán valores como 'abc', 'Abc', 'ABC', 'aBc', etc., pero no permitirán el mismo valor nuevamente si el caso coincide.

Tenga en cuenta que dar una colación "_bin" es diferente que usar el tipo de datos binarios.Por tanto, pruebe a hacer referencia a los siguientes enlaces:

  1. The BINARY and VARBINARY datatypes
  2. The _bin and binary Collations

espero que el anterior ayuda!

+0

¡Gracias por la respuesta! No veo cómo con esta solución habrá una búsqueda eficiente (O (log (n)) y no sensible a mayúsculas. – user1091141

+0

@ user1091141, por supuesto, puede hacer búsquedas insensibles a mayúsculas o minúsculas cambiando la intercalación, por ejemplo, consultas como 'SELECT * FROM dictionary DONDE un COLLATE utf8_general_ci = 'abc''. Disculpa si mi respuesta no fue clara pero supuse que podrías resolverlo, aquí hay un enlace - "http://dev.mysql.com/doc/refman/5.0 /en/case-sensitivity.html ". En cuanto a O (log (n)), lo siento pero mi matemática no es tan fuerte, pero no veo por qué la búsqueda sería ineficiente. Alternativamente, puede mantener 2' a 'columnas - una con intercalación general para búsquedas insensibles a mayúsculas y otra con _bin para inserciones sensibles a mayúsculas y minúsculas – Abhay

+2

si especifico una intercalación diferente en la cláusula-where que la definida en la definición de tabla, MySQL no usará el índice pero sí un escaneo completo de tablas. Los escaneos completos de tablas pueden tomar mucho tiempo para tablas grandes, por eso pueden ser como ineficiente Hacer 'EXPLAIN SELECT * FROM dictionary DONDE un COLLATE utf8_general_ci = 'abc'' muestra que se leen todas las filas de la tabla. Esto es al menos para mi versión de MySQL (5.0 y 5.1). Sería bueno si fuera diferente. – user1091141

1

Puede lograr esto agregando la columna adicional '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; 

Insertar que dice así:

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

Seleccione ahora puede distinguir entre mayúsculas y minúsculas:

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

Tenga en cuenta que la columna que tiene el índice en él, puede almacenar en el máximo de 191 caracteres . MySQL puede tener un índice máximo de 767 bytes, es decir, 767/4 (el unicode puede tomar hasta 4 bytes si usa la intercalación utf8mb4) = 191.75 = 191 caracteres. Si utiliza la intercalación utf8 que ocupa un máximo de 3 bytes por columna de caracteres puede almacenar a un máximo de 767/3 = 255 caracteres.

0
SELECT * FROM dictionary WHERE a COLLATE utf8_general_ci = 'abc' 

Prueba esto Funcionará ... funcionó para mí.

Cuestiones relacionadas