2008-10-15 9 views
63

Estoy ejecutando una base de datos MySQL localmente para el desarrollo, pero implementando en Heroku que usa Postgres. Heroku maneja casi todo, pero mis sentencias Like insensibles a mayúsculas y minúsculas se vuelven sensibles a las mayúsculas y minúsculas. Podría usar sentencias de iLike, pero mi base de datos MySQL local no puede manejar eso.¿Cómo se escribe una consulta sin distinción entre MySQL y Postgres?

¿Cuál es la mejor manera de escribir una consulta que no distinga entre mayúsculas y minúsculas y que sea compatible tanto con MySQL como con Postgres? ¿O debo escribir separadamente las declaraciones Like e iLike dependiendo de la base de datos con la que mi aplicación está hablando?

+4

Si está utilizando Postgres en la producción, utilice Postgres localmente también. Este no será el primer problema que encuentre, y también significa que no puede aprovechar nada específico de Postgres. –

Respuesta

57
select * from foo where upper(bar) = upper(?); 

Si establece el parámetro en mayúsculas en la persona que llama, puede evitar la segunda llamada a la función.

+11

También puede asegurarse de que sea superior: DONDE SUPERIOR (barra) = SUPERIOR (?) –

+2

No estoy 100% seguro, pero mi recuerdo es que esto no usará ningún índice que pueda estar presente en foo porque no puede escanear el valor de retorno de una función contra el índice. – richo

+5

@Richo: Pero puede crear un índice en 'upper (bar)' si lo necesita: http://www.postgresql.org/docs/current/interactive/sql-createindex.html –

13

en Postgres, usted puede hacer esto:

SELECT whatever FROM mytable WHERE something ILIKE 'match this'; 

No estoy seguro de si hay un equivalente para MySQL, pero siempre se puede hacer esto que es un poco feo pero debería funcionar tanto en MySQL y Postgres :

SELECT whatever FROM mytable WHERE UPPER(something) = UPPER('match this'); 
0

Conversión a superior es mejor, ya que cubre la sintaxis compatible para los 3 más usados ​​Rieles backends de bases de datos. PostgreSQL, MySQL y SQLite admiten esta sintaxis. Tiene el inconveniente (menor) de que tiene que escribir en mayúsculas su cadena de búsqueda en su aplicación o en su cadena de condiciones, lo que lo hace un poco más feo, pero creo que la compatibilidad que gana lo hace valioso.

Tanto MySQL como SQLite3 tienen un operador LIKE insensible a mayúsculas y minúsculas. Solo PostgreSQL tiene un operador LIKE sensible a las mayúsculas y minúsculas y un operador ILIKE específico de PostgreSQL (por el manual) para búsquedas que no distinguen entre mayúsculas y minúsculas. Puede especificar ILIKE insead de LIKE en sus condiciones en la aplicación Rails, pero tenga en cuenta que la aplicación dejará de funcionar en MySQL o SQLite.

Una tercera opción podría ser comprobar qué motor de base de datos está utilizando y modificar la cadena de búsqueda en consecuencia. Esto se puede hacer mejor pirateando/pausando los adaptadores de conexión de ActiveRecord y haciendo que el adaptador PostgreSQL modifique la cadena de consulta para sustituir "LIKE" por "ILIKE" antes de la ejecución de la consulta. Esta solución es, sin embargo, la más intrincada y, a la luz de formas más sencillas, como aplicar mayúsculas a ambos términos, creo que este no es el esfuerzo (aunque obtendría muchos puntos de brownie por hacerlo de esta manera).

+0

Empecé a trabajar en un complemento para hacer algo similar: http://github.com/myronmarston/case_insensitive_attributes Esto no se usa en producción en ningún lado , así que no huyas y no lo uses en tu aplicación, pero es un comienzo. –

1

También puede considerar consultar el searchlogic plugin, que hace el LIKE/ILIKE interruptor para usted.

74

La moraleja de esta historia es: No utilice una pila de software diferente para el desarrollo y la producción. Nunca.

Acabará con errores que no puede reproducir en dev; su prueba no tendrá valor. Simplemente no lo hagas.

El uso de un motor de base de datos diferente está fuera de discusión, habrá MUCHO más casos en que se comporte de manera diferente que simplemente LIKE (también, ¿ha revisado las intercalaciones en uso en las bases de datos? ¿Son idénticas en CADA CASO? no, puede olvidar ORDER BY en columnas varchar trabajando de la misma forma)

+4

+1 por el impulso moral, gracias. En serio, sin embargo, esto es correcto y mucho mejor que cualquiera de las respuestas de "solo responde la pregunta". Aunque odio estas respuestas morales de la historia en general, pero en este caso está bien hecho. –

+3

El objetivo de AR/AM es permitirle utilizar diferentes back-ends de bases de datos en desarrollo y producción.En mi opinión, el error aquí está en cómo las consultas son generadas por AR/AM. –

+0

@christopher Maujean: consulte http://www.joelonsoftware.com/articles/LeakyAbstractions.html para saber por qué esta es una mala idea. – MarkR

2

Si está usando PostgreSQL 8.4 puede usar el módulo citext para crear campos de texto que no distingan entre mayúsculas y minúsculas.

+1

O agregue un índice funcional: http://www.postgresql.org/docs/7.3/static/indexes-functional.html – troelskn

1

También puede usar ~ * en postgres si desea hacer coincidir una subcadena dentro de un bloque. ~ coincide con la subcadena sensible a las mayúsculas y minúsculas, ~ * subcadena insensible a mayúsculas y minúsculas. Es una operación lenta, pero podría ser útil para las búsquedas.

Select * from table where column ~* 'UnEvEn TeXt'; 
Select * from table where column ~ 'Uneven text'; 

Tanto habría dado con "Parte del texto desigual aquí" sólo el primero golpearía en "Algunos irregulares del texto aquí"

36

Uso Arel:

Author.where(Author.arel_table[:name].matches("%foo%")) 

matches utilizará el operador ILIKE para Postgres, y LIKE para todo lo demás.

+2

Desearía poder dar más de +1 ... ¡Nunca supe que Arel podría hacer esto! ¿Tal vez porque está casi completamente indocumentado? Hm ... –

+0

Sí --- ¿Está documentado en alguna parte? – Dogweather

8

Hay varias respuestas, ninguna de las cuales son muy satisfactorios.

  • INFERIOR (bar) = BAJA se trabajo en MySQL y Postgres, pero es probable que realizar terriblemente en MySQL (?): MySQL no usará sus índices debido a la función INFERIOR. En Postgres puede agregar un índice funcional (en LOWER (barra)) pero MySQL no es compatible con esto.
  • MySQL hará (a menos que haya configurado una distinción entre mayúsculas y minúsculas collation) hacer coincidir mayúsculas y minúsculas de forma automática, y utilizar sus índices. (bar =?).
  • Desde su código fuera de la base de datos, mantener la barra de y bar_lower campos, donde bar_lower contiene el resultado de inferior (bar). (Esto también puede ser posible usando desencadenadores de base de datos). (Consulte una explicación de esta solución en Drupal). Esto es torpe, pero al menos se ejecuta de la misma manera en casi todas las bases de datos.
+0

Bueno, gracias por el punto 2, descubrí que, de hecho, no distingue entre mayúsculas y minúsculas. – ADTC

5

REGEXP es sensible a mayúsculas (a no ser utilizado con el binario), y se puede utilizar, al igual que ...

SELECT id FROM person WHERE name REGEXP 'john'; 

... para que coincida con 'John', 'John', 'John' , etc.

+0

¡Esto es asombroso! Puedo usar '|' para tener varias palabras clave de búsqueda. – ADTC

+0

mientras que las expresiones regulares son extremadamente versátiles, tenga en cuenta que son bastante lentas y lo notará en conjuntos de datos más grandes o servidores lentos – aydow

Cuestiones relacionadas