2010-11-20 9 views
3

Ich habe eine Mitglieder-Suchfunktion, wo Sie Teile von Namen geben können und die Rückkehr sollte alle Mitglieder mit mindestens einem der Benutzernamen, Vornamen oder Nachnamen mit dieser Eingabe übereinstimmen. Das Problem hier ist, dass einige Namen "komische" Zeichen wie die é in Renée haben und der Benutzer nicht das seltsame Zeichen, aber den normalen ASCII-Ersatz e eingeben möchte.Wie konvertiere ich eine Spalte im laufenden Betrieb ohne Speichern, um nach Übereinstimmungen mit einer externen ASCII-Zeichenkette zu suchen?

In PHP konvertiere ich den Eingabe-String mit iconv in ASCII (nur für den Fall, dass jemand seltsame Zeichen eingibt). In der Datenbank sollte ich jedoch auch die seltsamen Zeichen in ASCII umwandeln (offensichtlich), damit die Zeichenfolgen übereinstimmen.

Ich habe versucht, die folgenden:

SELECT 
    CONVERT(_latin1'Renée' USING ascii) t1, 
    CAST(_latin1'Renée' AS CHAR CHARACTER SET ASCII) t2; 

(Das sind zwei Versuche.) Beide funktionieren nicht. Beide haben Ren?e als Ausgabe. Das Fragezeichen sollte ein e sein. Es ist in Ordnung, wenn es Ren?ee ausgibt, da ich alle Fragezeichen nach der Konvertierung nur entfernen kann.

Wie Sie sich vorstellen können, sind die Spalten, die ich abfragen möchte, Latin1 codiert.

Danke.

+0

Ist das auf andere Weise möglich? Zu viel Freiheit ist in Ordnung, ich filtere die Ergebnisse nur mit PHP nach dem Filter in MySQL. Z.B. Ich bin gut darin, "Renee", "Renée" und "Renae" und "Renõe" als MySQL-Ergebnisse zu bekommen, wenn ich "Renee" eingib. Sowieso?? – Rudie

+0

Der beste Weg wäre, die Spiele zu speichern. Die Konvertierung im laufenden Betrieb ist für große Datenmengen extrem langsam, da sie nicht index-intelligent ist. – Pacerier

Antwort

6

Sie müssen nichts konvertieren. Ihre Anforderung besteht darin, zwei Strings zu vergleichen und zu fragen, ob sie gleich sind und Akzente ignorieren. der Datenbankserver kann eine collation verwenden, die für Sie tun:

Nicht UCA Sortierungen haben eine Eins-zu-Eins-Abbildung von Zeichencode auf das Gewicht. In MySQL sind solche Sortierungen case unempfindlich und akzentunempfindlich. utf8_general_ci ist ein Beispiel: 'a', 'A', 'À' und 'á' haben unterschiedliche Zeichencodes, aber alle haben ein Gewicht von 0x0041 und vergleichen als gleich.

mysql> SET NAMES 'utf8' COLLATE 'utf8_general_ci'; 
Query OK, 0 rows affected (0.00 sec) 

mysql> SELECT 'a' = 'A', 'a' = 'À', 'a' = 'á'; 
+-----------+-----------+-----------+ 
| 'a' = 'A' | 'a' = 'À' | 'a' = 'á' | 
+-----------+-----------+-----------+ 
|   1 |   1 |   1 | 
+-----------+-----------+-----------+ 
1 row in set (0.06 sec) 
+1

das obige ist nicht wahr, der Datenspeicher ist latin1, und OP möglicherweise UTF-8 in Seitencodierung nicht anwenden – ajreal

+1

Unglücklicherweise (?), Die nicht funktioniert. Ich versuche 'ID von Mitgliedern auszuwählen, deren Nachname wie 'test6e%'' (mit einem Wert für 'lastname' von' 'test6ë'') ist. Keine Datensätze zurückgegeben. Die Datenbank, Tabelle und Spalte sind UTF8. Wenn ich 'Reneé '=' Renee ',' Renëe '=' Renee 'auswähle,' 'geben sie wahr zurück. Seltsam? – Rudie

+0

@Rudie: Funktioniert gut in meiner Umgebung, aber sehen Sie sich meine Antwort für Erklärungen/Genauigkeiten an. – Danosaure

3

Der Operator CAST() im Zusammenhang mit Zeichenkodierungen übersetzt von einer Methode der Zeichenspeicherung zu einer anderen - es ändert nicht die tatsächlichen Zeichen, die Sie suchen. Ein é-Zeichen steht in jedem Zeichensatz, es ist kein e. Sie müssen akzentuierte Zeichen in nicht akzentuierte Zeichen konvertieren. Dies ist ein anderes Problem und wurde bereits mehrmals gestellt (normalizing accented characters in MySQL queries).

Ich bin nicht sicher, ob es eine Möglichkeit gibt, dies direkt in MySQL zu tun, kurz davor, eine Übersetzungstabelle zu haben und Buchstabe für Buchstabe durchzugehen. Es wäre wahrscheinlich einfacher, ein PHP-Skript zu schreiben, um durch die Datenbank zu gehen und die Übersetzungen zu machen.

+0

Ich möchte die 'Übersetzungen' nicht speichern. Die Übersetzungen dienen nur zur Suche. Die Anzeigeergebnisse sollten so sein wie sie sind: mit Akzenten und anderen exotischen Zeichen. Wenn PHP eine Funktion dafür hat (iconv), warum nicht MySQL? Das will ich nicht (will)! – Rudie

+1

@Rudie PHP hat sehr viele Funktionen, die MySQL nicht hat. SQL-Sprachen sind in Bezug auf ihre Standardbibliothek meist sehr leicht. Es wäre möglich, eine Funktion zu schreiben, um das zu erreichen, was Sie wünschen, obwohl die Leistung vielleicht nicht fantastisch ist, es sei denn, Sie haben sie als UDF oder native Funktion geschrieben (obwohl Sie mit letzterer die iconv-Bibliothek aufrufen könnten). – Orbling

3

@vincebowdren Antwort oben genannten Arbeiten, ich hinzufüge, nur dies als eine Antwort für die Formatierung Zwecke:

CREATE TABLE `members` (
    `id` int(11) DEFAULT NULL, 
    `lastname` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL 
); 
insert into members values (1, 'test6ë'); 
select id from members where lastname like 'test6e%';

Yields

+------+ 
| id | 
+------+ 
| 1 | 
+------+

Und mit Latin1,

set names latin1; 
CREATE TABLE `members2` (
    `id` int(11) DEFAULT NULL, 
    `lastname` varchar(20) CHARACTER SET latin1 DEFAULT NULL 
); 
insert into members2 values (1, 'Renée'); 
select id from members2 where lastname like '%Renee%';

nachgeben:

+------+ 
| id | 
+------+ 
| 1 | 
+------+

Natürlich sollte die OP die gleiche charset in der Anwendung hat (PHP), die Verbindung (MySQL unter Linux verwendet in 5,0 bis latin1 auf Standard, aber standardmäßig auf UTF-8 in 5.1) und im Feld Datentyp, um weniger Unbekannte zu haben. Sortierungen kümmern sich um den Rest.

EDIT: Ich schrieb sollte eine bessere Kontrolle über alles haben, aber folgendes funktioniert auch:

set names latin1; 
select id from members where lastname like 'test6ë%';

Denn sobald die Verbindung charset gesetzt, MySQL die Umwandlung intern tut. In diesem Fall wird es konvertiert konvertieren und vergleichen Sie die UTF8-Zeichenfolge (von DB) mit dem Latin1 (aus Abfrage).

EDIT 2: Einige Skepsis mich erfordert ein noch überzeugendes Beispiel zu bieten:

die Aussagen oben gegeben, hier, was ich mehr tat. Stellen Sie sicher, dass das Terminal in UTF8 ist. Denken Sie daran,

set names utf8; 
insert into members values (5, 'Renée'), (6, 'Renêe'), (7, 'Renèe'); 
select members.id, members.lastname, members2.id, members2.lastname 
from members inner join members2 using (lastname);

dass members in UTF-8 ist und members2 ist in latin1.

+------+----------+------+----------+ 
| id | lastname | id | lastname | 
+------+----------+------+----------+ 
| 5 | Renée | 1 | Renée | 
| 6 | Renêe | 1 | Renée | 
| 7 | Renèe | 1 | Renée | 
+------+----------+------+----------+

was mit den richtigen Einstellungen beweist, erledigt die Sortierung die Arbeit für Sie.

+0

@Danosaure - ist nicht wahr, was du vergleichst auf 'Renée' ist ein UTF8, kein latin1 (iso-8859- *) – ajreal

+0

@ajreal: Es ist übersetzt. Ich habe es vor dem Posten getestet. Sie müssen Ihre Umgebung entsprechend konfigurieren (Terminal, Verbindung und Sortierung). Hast du es getestet, bevor ich gesagt habe, dass ich falsch liege? – Danosaure

+0

@Danosaure - offensichtlich haben Sie es falsch verstanden ... Ihre Methode geht davon aus, dass alle Zeichen in utf-8 sind, was nicht wahr ist. meine Hinweise zu Ihnen, verwenden Sie 'char_length' – ajreal

4

Zunächst einmal sollte es so funktionieren:

SELECT * FROM `test` WHERE `name` COLLATE utf8_general_ci LIKE '%renee%'; 

Wo die test Tabelle ist:

+-----+--------+ 
| id | name | 
+-----+--------+ 
| 1 | Renée | 
| 2 | Renêe | 
| 3 | Renee | 
+-----+--------+ 

Was ist Ihre MySQL-Version und wie versuchen Sie die Dinge passen?


Einer der anderen möglichen Lösungen ist Umschrift.

Verwandte: PHP Transliteration

Transliteration des Eingangs sollte kein Problem sein, aber Transliteration die Werte aus dem permanenten Speicher (z db) in Echtzeit während der Suche nicht durchführbar sein. So können Sie drei weitere Felder hinzufügen: username_slug, firstname_slug und lastname_slug. Beim Einfügen/Ändern eines Datensatzes legen Sie die Slug-Werte entsprechend fest.Suchen Sie bei der Suche die transliterierte Eingabe nach diesen Slug-Feldern.

+------+----------+---------------+----------+---------------+ ... 
| id | username | username_slug | lastname | lastname_slug | ... 
+------+----------+---------------+----------+---------------+ ... 
| 1 | Renée | renee  | La Niña | la-nina  | ... 
| 2 | Renêe | renee  | ...  | ...   | ... 
| 3 | Renee | renee  | ...  | ...   | ... 
+------+----------+---------------+----------+---------------+ ... 

Eine Suche nach „renee“ oder „Renée“ würde alle Datensätze übereinstimmen.

Als Nebeneffekt können Sie möglicherweise diese Felder zum Generieren SEF (suchmaschinenfreundliche) Links verwenden, daher werden sie ..._slug genannt, z. example.com/users/renee. In diesem Fall sollten Sie natürlich die Eindeutigkeit des Slug-Feldes überprüfen.

+0

Es könnte eine gute Idee am Anfang sein, aber diese Art von Setup ist ein Albtraum ... es sei denn, Sie haben ein solides Framework und niemand wird die Datenbank jemals direkt manuell aktualisieren. Ich würde wirklich eine Echtzeit-Transliteration bevorzugen, anstatt sie in der Datenbank zu speichern. – Danosaure

+0

Normalerweise ja, aber De-Normalisierung ist in der Regel auf dem Weg, wenn Leistung beginnt zu stören :) –

Verwandte Themen