2008-10-15 10 views
63

Używam lokalnie bazy danych MySQL do rozwoju, ale wdrażam do Heroku, który używa PostgreSQL. Heroku obsługuje prawie wszystko, ale moje rozróżnianie wielkości liter nie ma znaczenia. Mogę używać instrukcji iLike, ale moja lokalna baza danych MySQL nie może tego obsłużyć.Jak napisać zapytanie nie uwzględniające wielkości liter dla MySQL i PostgreSQL?

Jaki jest najlepszy sposób napisania zapytania nie uwzględniającego wielkości liter, zgodnego zarówno z MySQL, jak i Postgresem? Czy muszę napisać osobne instrukcje jak i iLike w zależności od bazy danych, z którą rozmawia moja aplikacja?

+4

Jeśli używasz PostgreSQL w prodution, korzystaj również z PostgreSQL. Nie będzie to pierwszy numer, na który napotkasz, a także oznacza, że ​​nie możesz wykorzystać niczego, co jest specyficzne dla PostgreSQL. –

Odpowiedz

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

Jeśli ustawisz parametr na duże litery w programie wywołującym, możesz uniknąć drugiego wywołania funkcji.

+11

Możesz również upewnić się, że jest górny: WHERE UPPER (bar) = UPPER (?) –

+2

Nie jestem w 100% pewny, ale moim wspomnieniem jest to, że nie użyje on żadnych indeksów, które mogą być obecne na foo, ponieważ nie może zeskanuj wartość zwracaną przez funkcję do indeksu. – richo

+5

@Richo: Ale możesz utworzyć indeks w 'górnym pasku (bar), jeśli potrzebujesz: http://www.postgresql.org/docs/current/interactive/sql-createindex.html –

13

W PostgreSQL, można to zrobić:

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

Nie jestem pewien, czy istnieje odpowiednik dla MySQL, ale zawsze można to co jest trochę brzydki, ale powinien działać zarówno w MySQL i PostgreSQL zrobić :

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

Konwersja do górnej jest najlepsza, ponieważ obejmuje kompatybilną składnię dla 3 najczęściej używanych baz danych Railsów. PostgreSQL, MySQL i SQLite obsługują tę składnię. Ma (drugorzędną) wadę, że musisz wpisać w łańcuch wielkie litery w swojej aplikacji lub w swoim łańcuchu warunków, co sprawia, że ​​jest trochę brzydsza, ale myślę, że kompatybilność, którą zyskujesz, sprawia, że ​​jest warta zachodu.

Zarówno MySQL, jak i SQLite3 mają operatora LIKE niezależnego od wielkości liter. Tylko PostgreSQL ma rozróżniany wielkość liter LIKE operatora i specyficzny dla PostgreSQL (zgodnie z instrukcją) operator ILIKE dla wyszukiwań niewrażliwych na wielkość liter. Możesz podać ILIKE inaczej z LIKE w twoich warunkach w aplikacji Rails, ale pamiętaj, że aplikacja przestanie działać pod MySQL lub SQLite.

Trzecią opcją może być sprawdzenie, który silnik bazy danych jest używany i odpowiednio zmodyfikować ciąg wyszukiwania. Można to zrobić lepiej poprzez włamywanie się do adapterów połączenia ActiveRecord/monkeypatching i modyfikowanie ciągu zapytań przez adapter PostgreSQL w celu zastąpienia "LIKE" dla "ILIKE" przed wykonaniem zapytania. To rozwiązanie jest jednak najbardziej zawiłe iw świetle łatwiejszych sposobów, jak na przykład obstawianie obu terminów, myślę, że to nie jest wysiłek (chociaż dostaniesz dużo ciastek za robienie tego w ten sposób).

+0

Zacząłem pracować nad wtyczką, aby zrobić coś podobnego: http://github.com/myronmarston/case_insensitive_attributes To nie jest używane w produkcji gdziekolwiek , więc nie uciekaj i używaj go w swojej aplikacji, ale to dopiero początek. –

1

Możesz także rozważyć wypróbowanie wtyczki searchlogic, która przełącza dla Ciebie przełącznik .

74

Morał tej historii brzmi: Nie używaj innego stosu oprogramowania do programowania i produkcji. Nigdy.

Po prostu skończysz z błędami, których nie możesz odtworzyć w dev; twoje testy będą bezwartościowe. Po prostu tego nie rób.

Używanie innego silnika bazy danych jest wykluczone - DUŻO więcej przypadków zachowa się inaczej niż LIKE (również, czy sprawdziłeś zbiory używane przez bazy danych - czy są one identyczne w KAŻDYM PRZYPADKU? nie, możesz zapomnieć ORDER BY na kolumnach varchar działających tak samo)

+4

+1 za moralny impuls, dzięki. Poważnie, jednak jest to słuszne i dużo lepsze niż odpowiedzi "tylko odpowiedz na pytanie". Chociaż nienawidzę tych moralnych opowieści w ogólności, ale w tym przypadku jest dobrze zrobione. –

+3

Cały punkt AR/AM polega na umożliwieniu korzystania z różnych baz danych w rozwoju i produkcji.Moim zdaniem, wadą jest to, w jaki sposób generowane są zapytania przez AR/AM. –

+0

@christopher Maujean: zobacz http://www.joelonsoftware.com/articles/LeakyAbstractions.html, dlaczego nie jest to zły pomysł. – MarkR

2

Jeśli korzystasz z PostgreSQL 8.4, możesz użyć modułu citext, aby utworzyć pola tekstowe niewrażliwe na wielkość liter.

+1

Lub dodaj indeks funkcjonalny: http://www.postgresql.org/docs/7.3/static/indexes-functional.html – troelskn

1

Możesz również użyć ~ * w postgresie, jeśli chcesz dopasować podciąg w obrębie bloku. ~ dopasowuje wielkość liter do podszycia, ~ * rozróżnianie wielkości liter. Jest to powolna operacja, ale może się przydać do wyszukiwania.

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

Zarówno byłoby trafić na „jakiś Nierówna tekst tutaj” Jedynie były by trafić na „jakiś nierówny tekst”

36

Zastosowanie AREL:

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

matches użyje operatora ILIKE dla Postgres i LIKE dla wszystkich pozostałych.

+2

Chciałbym dać więcej niż +1 ... Nigdy nie wiedziałem, że Arel może to zrobić! Może dlatego, że jest prawie całkowicie nieudokumentowana? Hm ... –

+0

Tak --- IS to jest udokumentowane w dowolnym miejscu? – Dogweather

8

Istnieje kilka odpowiedzi, z których żadna nie są bardzo zadowalające.

  • DOLNA (bar) = DOLNY będzie praca na MySQL i PostgreSQL, ale jest prawdopodobne, aby wykonać strasznie na MySQL (?): MySQL nie użyje swoich indeksów ze względu na niższą funkcję. Na Postgres można dodać indeks funkcjonalny (na LOWER (bar)), ale MySQL nie obsługuje tego.
  • MySQL będzie (o ile nie ustawiono rozróżniania małych i wielkich liter) collation), jeśli nie będzie uwzględniana wielkość liter w dopasowaniu automatycznie, i użyje indeksów. (słupek =?).
  • z kodu poza bazą danych, utrzymanie poprzeczkę i bar_lower pól, gdzie bar_lower zawierający wynik niższy (bar). (Może to być również możliwe za pomocą wyzwalaczy bazy danych). (Zobacz omówienie tego rozwiązania na Drupal). Jest to niezgrabne, ale działa przynajmniej tak samo na prawie każdej bazie danych.
+0

Cóż, dziękuję za punkt 2, odkryłem, że domyślnie jest to niewrażliwe na wielkość liter. – ADTC

5

REGEXP nie uwzględnia wielkości liter (chyba że używany z binarny) i mogą być używane, tak jak ...

SELECT id FROM person WHERE name REGEXP 'john'; 

... dopasować 'John', 'John', 'John' itp.

+0

To jest niesamowite! Mogę użyć '|', aby mieć wiele słów kluczowych w wyszukiwaniu. – ADTC

+0

podczas gdy regexpy są niezwykle uniwersalne, należy pamiętać, że są one dość powolne i można to zauważyć na większych zestawach danych lub wolnych serwerach – aydow