PostgreSQL: cómo hacer una consulta "sin distinción entre mayúsculas y minúsculas"

339

¿Hay alguna forma de escribir consultas que no distingan entre mayúsculas y minúsculas en PostgreSQL, por ejemplo, quiero que las siguientes 3 consultas devuelvan el mismo resultado?

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'
Jame
fuente
si citext viene con su instalación de Postgres, intente con el tipo citext. Es un texto que no distingue entre mayúsculas y minúsculas
Michael Buen
2
Para los recién llegados a esta pregunta, este enlace a la documentación oficial de postgres contiene todas las respuestas dadas aquí, así como algunas otras opciones.
Parthian Shot
Sir reasigne la respuesta aceptada a la hecha por @Arun por favor. Es mucho menos complicado y no tiene muchos problemas después de la solicitud.
zeliboba

Respuestas:

451

Use la función INFERIOR para convertir las cadenas a minúsculas antes de comparar.

Prueba esto:

SELECT id 
  FROM groups
 WHERE LOWER(name)=LOWER('Administrator')
Chandu
fuente
92
Es importante tener en cuenta que el uso de LOWER (o cualquier función) en las columnas de predicados, en este caso "nombre", hará que los índices ya no sean buscables. Si esta es una tabla grande o consultada con frecuencia, eso podría causar problemas. La clasificación sin distinción entre mayúsculas y minúsculas, el texto cite o un índice basado en funciones mejorará el rendimiento.
Jordania
108
O simplemente cree un índice como este: CREATE INDEX idx_groups_name ON groups lower (name);
Daniel
19
También especifique varchar_pattern_opssi desea que el índice funcione con la LIKE 'xxx%'consulta, es decir CREATE INDEX ix_groups_name ON groups (lower(name) varchar_pattern_ops).
sayap
10
El uso del operador ILIKE (como se muestra en otras respuestas a continuación) es un enfoque más simple, a pesar de que esta es la respuesta más votada.
Ryan
55
Revisando los comentarios aquí, muchas sugerencias aquí sugieren ILIKE, funcionará but with slow response,. Para obtener un acceso rápido a las tablas en función de los resultados de los cálculos, sugiero que cualquiera que solo verifique esto deba ir con la respuesta aceptada. Ver más detalles aquí y aquí
Afolabi Olaoluwa Akinwumi
231

usando en ILIKElugar deLIKE

SELECT id FROM groups WHERE name ILIKE 'Administrator'
Mohammad Reza Norouzi
fuente
1
Tenga en cuenta que ILIKEno es compatible con Hibernate cuando se usa en Spring Boot.
el AnT
@AnT funciona con org.hibernate.dialect.PostgreSQL94DialectSpring Boot 2.0.6.RELEASE. Pero IntelliJ se queja de eso.
Samintha Kaveesh
134

El enfoque más común es minúsculas o mayúsculas en la cadena de búsqueda y los datos. Pero hay dos problemas con eso.

  1. Funciona en inglés, pero no en todos los idiomas. (Tal vez ni siquiera en la mayoría de los idiomas). No todas las letras minúsculas tienen una letra mayúscula correspondiente; no todas las letras mayúsculas tienen una letra minúscula correspondiente.
  2. El uso de funciones como lower () y upper () le dará un escaneo secuencial. No puede usar índices. En mi sistema de prueba, el uso de lower () tarda aproximadamente 2000 veces más que una consulta que puede usar un índice. (Los datos de prueba tienen un poco más de 100k filas).

Existen al menos tres soluciones de uso menos frecuente que podrían ser más efectivas.

  1. Utilice el módulo citext , que imita principalmente el comportamiento de un tipo de datos que no distingue entre mayúsculas y minúsculas. Una vez cargado ese módulo, puede crear un índice que no distinga entre mayúsculas y minúsculas CREATE INDEX ON groups (name::citext);. (Pero ver más abajo).
  2. Use una colación que no distinga entre mayúsculas y minúsculas. Esto se establece cuando inicializa una base de datos. El uso de una intercalación que no distingue entre mayúsculas y minúsculas significa que puede aceptar casi cualquier formato del código del cliente, y aún así obtendrá resultados útiles. (También significa que no puede hacer consultas que distingan entre mayúsculas y minúsculas. Duh).
  3. Crea un índice funcional. Cree un índice en minúsculas usando CREATE INDEX ON groups (LOWER(name));. Una vez hecho esto, puede aprovechar el índice con consultas como SELECT id FROM groups WHERE LOWER(name) = LOWER('ADMINISTRATOR');, o SELECT id FROM groups WHERE LOWER(name) = 'administrator';debe recordar usar LOWER (), sin embargo.

El módulo citext no proporciona un tipo de datos que no distinga entre mayúsculas y minúsculas. En cambio, se comporta como si cada cadena estuviera en minúscula. Es decir, se comporta como si hubiera llamado lower()a cada cadena, como en el número 3 anterior. La ventaja es que los programadores no tienen que recordar cadenas en minúsculas. Pero debe leer las secciones "Comportamiento de comparación de cadenas" y "Limitaciones" en los documentos antes de decidir utilizar citext.

Mike Sherrill 'Retiro del gato'
fuente
1
Acerca del n. ° 1: No debería ser un problema, ya que serían dos cadenas diferentes (piense en ello como hacer col = 'a'y col = 'b'). Acerca del n. ° 2: como dijiste, puedes crear un índice en una expresión, por lo que no es realmente un problema. Pero estoy de acuerdo con usted en que cambiar la clasificación es probablemente la mejor solución.
Vincent Savard
55
¿Alguien puede decirme qué intercalaciones entre mayúsculas y minúsculas son las intercalaciones integradas de PostgreSQL? ¿Veo esto como una opción, pero no puedo encontrar nada sobre una intercalación entre mayúsculas y minúsculas para Postgres en la red?
khorvat
1
@AnupShah: No, no estoy diciendo eso. No estoy ejecutando PostgreSQL en Windows. Los documentos 9.4 dicen esto : "En todas las plataformas, las intercalaciones denominadas default, C y POSIX están disponibles. Es posible que existan intercalaciones adicionales dependiendo del soporte del sistema operativo". Puede ver con qué colaciones PostgreSQL cree que están disponibles select * from pg_collation;.
Mike Sherrill 'Cat Recall'
1
@ Matthieu: Esta es la mejor introducción (y precaución) al tema que conozco: Casos de borde para tener en cuenta. Parte 1 - Texto .
Mike Sherrill 'Cat Recall'
1
@ Matthieu: las preguntas frecuentes de Unicode también son divertidas de leer. He aquí por qué no hay un carácter en mayúscula único . .
Mike Sherrill 'Cat Recall'
95

Puedes usar ILIKE. es decir

SELECT id FROM groups where name ILIKE 'administrator'
ADJ
fuente
Es correcto y funciona bien para mí, estoy usando MAC OS X (Mountain Lion).
ADJ
55
Esto funcionará, pero con una respuesta lenta. Para obtener un acceso rápido a las tablas en función de los resultados de los cálculos, sugiero utilizar la lowerfunción. Ver más detalles
Afolabi Olaoluwa Akinwumi
1
@AfolabiOlaoluwaAkinwumi fundamentalmente esto se reduce a si está buscando resultados en lugar de filtrar valores conocidos . En el último caso, debe persistir un único caso uniforme a nivel de datos que permita que funcione el operador de igualdad. [La recomendación personal es mayúscula para los valores del código de tipo]
Chris Marisic
53

También puede leer sobre la ILIKEpalabra clave. A veces puede ser bastante útil, aunque no se ajusta al estándar SQL. Consulte aquí para obtener más información: http://www.postgresql.org/docs/9.2/static/functions-matching.html

Priidu Neemre
fuente
99
Algo a tener en cuenta aquí es la entrada maliciosa del usuario. Si ejecuta una consulta como email ILIKE 'user-input-email-here', asegúrese de escapar de la entrada del usuario. De lo contrario, las personas pueden ingresar caracteres como% que coinciden con cualquier cosa.
Matt De Leon
2
@MattDeLeon Hola. Bien dicho. Pero solo quiero preguntarte si uso ILIKEy prepared statements¿esto me protegerá sql injection?
slevin
No estoy seguro, supongo que desea enviar una cadena de escape a la declaración preparada.
Matt De Leon el
1
"La palabra clave ILIKE se puede usar en lugar de LIKE para hacer que la coincidencia no distinga entre mayúsculas y minúsculas de acuerdo con la configuración regional activa. Esto no está en el estándar SQL pero es una extensión PostgreSQL". Funciona como un encanto en 9.3
Aleksey Deryagin
1
ILIKE es más lento que lower(column_name) like %expression%.
Patryk Imosa
28

También puede usar expresiones regulares POSIX, como

SELECT id FROM groups where name ~* 'administrator'

SELECT 'asd' ~* 'AsD' devoluciones t

James Brown
fuente
1
Tuve el mismo problema, necesitaba búsquedas sin distinción entre mayúsculas y minúsculas en mi base de datos PostgreSQL. Pensé en transformar la cadena de entrada del usuario en una expresión regular. ¡Ahora, usar ~ * en lugar de = o LIKE funcionó perfectamente! No necesitaba crear nuevos índices, columnas o lo que sea. Claro, la búsqueda de expresiones regulares es más lenta que la comparación de bytes directos, pero no creo que el impacto en el rendimiento sea mucho mayor que tener que manejar dos conjuntos de datos (uno inferior o en mayúscula solo para buscar, luego tener que recuperar el original correspondiente datos del otro conjunto). Además, esto es más limpio!
Cyberknight el
1
Bien, pero ¿cómo hacer con regexp_matches () por ejemplo?
WKT
De acuerdo con los documentos de postgres: El operador ~~ es equivalente a LIKE, y ~~ * corresponde a ILIKE. También hay operadores! ~~ y! ~~ * que representan NOT LIKE y NOT ILIKE, respectivamente. Todos estos operadores son específicos de PostgreSQL.
sh4
Me enfrenté a un problema cuando se incluyen paréntesis en el texto, no funciona. como: "código (LC)"
Oshan Wisumperuma el
8

El uso ~*puede mejorar en gran medida el rendimiento, con la funcionalidad de INSTR.

SELECT id FROM groups WHERE name ~* 'adm'

devolver filas con nombre que contiene OR es igual a 'adm'.

Robin Goh
fuente
1
Hola Robin, bienvenido a SO. La respuesta de James Brown ya propuso esta solución. Además, su respuesta propuesta no aprovecha la expresión regular de ninguna manera.
Rafael