2010-11-20 2 views
3

저는 회원 검색 기능을 가지고 있습니다. 여기서 이름의 일부를 제공 할 수 있으며 반환 값은 해당 입력과 일치하는 사용자 이름, 이름 또는 성 중 적어도 하나를 갖는 모든 회원이어야합니다. 여기서 문제는 é과 같은 일부 이름에 '이상한'문자가 있고 사용자가 이상한 문자를 입력하지 않고 일반 ASCII 대신 e을 입력한다는 것입니다.외부 ASCII 문자열과 일치하는지 확인하기 위해 저 장하지 않고 열을 ASCII로 ASCII로 변환하려면 어떻게해야합니까?

PHP에서 나는 iconv를 사용하여 입력 문자열을 ASCII로 변환합니다 (사람이 이상한 문자를 입력 한 경우). 그러나 데이터베이스에서 나는 또한 일치하는 문자열에 이상한 문자를 ASCII (분명히)로 변환해야합니다.

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

(즉, 두 개의 시도를합니다.) 모두 작동하지 않습니다

나는 다음 시도했다. 둘 다 Ren?e을 출력합니다. 물음표는 e이어야합니다. 변환 후 모든 물음표를 제거 할 수 있으므로 Ren?ee을 출력해도 괜찮습니다.

상상할 수있는 것처럼 쿼리하려는 열은 Latin1로 인코딩됩니다.

감사합니다.

+0

다른 방법으로 가능합니까? 너무 많은 자유는 괜찮습니다. MySQL의 필터 다음에 엄격하게 PHP로 결과를 필터링 할 것입니다. 예 : "Renee"를 입력 할 때 MySQL 결과로 "Renene", "Renée"및 "Renene"를 얻는 것이 좋습니다. 어쨌든?? – Rudie

+0

가장 좋은 방법은 경기를 저장하는 것입니다. 인덱스 스마트하지 않기 때문에 거대한 데이터의 변환은 매우 느립니다. – Pacerier

답변

6

아무 것도 변환 할 필요가 없습니다. 귀하의 요구 사항은 두 개의 문자열을 비교하고 그들이 동등한 지, 액센트를 무시 하는지를 묻는 것입니다. 데이터베이스 서버는 당신을 위해 할 수있는 collation를 사용할 수 있습니다

비 UCA 데이터 정렬은 문자 코드에서 무게 일대일 매핑을 가지고있다. MySQL에서 이러한 데이터 정렬은 이고 대/소문자를 구분하지 않습니다. utf8_general_ci는 예입니다. 'a', 'A', 'À'및 'á'는 각각 문자 코드가 다르지만 모두 0x의 0x0041이며 동일한 것으로 비교됩니다.위의 작품

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

위 내용은 사실이 아니며 데이터 저장소는 latin1이고 OP는 UTF-8을 페이지 인코딩에 적용하지 않을 수도 있습니다 – ajreal

+1

불행하게도 (?) 작동하지 않습니다. 나는 'test6e %'('test6ë'의'lastname '값과 함께)와 같은 lastname 멤버로부터'select id를 시도한다. 레코드가 반환되지 않았습니다. 데이터베이스, 테이블 및 열은 UTF8입니다. 'Renee'= 'Renee', 'Renëe'= 'Renee'를 선택하면 실제로 돌아갑니다. 기묘한? – Rudie

+0

@ 루디 : 내 환경에서는 잘 작동하지만 설명/정밀도에 대한 내 대답을보십시오. – Danosaure

3

문자 인코딩의 컨텍스트에서 CAST() 연산자는 문자 저장 방법 중 하나에서 다른 것으로 변환합니다. 실제 문자는 사용자가 변경 한 것이 아닙니다. é 문자는 모든 문자 집합에있는 문자이며 e 문자가 아닙니다. 악센트 부호가있는 문자를 다른 악센트 부호가없는 문자로 변환해야합니다. 다른 문제이며 이전에 여러 번 묻습니다 (normalizing accented characters in MySQL queries).

MySQL에서 직접이 작업을 수행 할 수있는 방법이 있는지 확신 할 수는 없지만 번역 테이블이 있어야하고 편지를 통해 편지를 보내지 않는 것이 좋습니다. PHP를 작성하여 데이터베이스를 통해 번역하는 것이 더 쉬울 것입니다.

+0

'번역'을 저장하고 싶지 않습니다. 번역은 검색 전용입니다. 표시 결과는 그대로 : 액센트 및 기타 이국적인 문자로 표시되어야합니다. PHP가 그것을위한 함수를 가지고 있다면 (iconv), 왜 MySQL이 아닌가? 나는 그것을 믿기를 원하지 않는다! – Rudie

+1

@Rudie PHP에는 MySQL에없는 많은 기능이 있습니다. SQL 언어는 표준 라이브러리 측면에서 매우 가벼운 경향이 있습니다. UDF 또는 네이티브 함수로 작성하지 않으면 성능이 좋지 않을 수도 있지만 원하는대로 달성하는 함수를 작성할 수 있습니다 (단, 후자의 경우 iconv 라이브러리를 호출 할 수는 있지만). – Orbling

3

@vincebowdren 대답, 난 그냥 포맷 목적에 대한 응답으로이 추가 해요 :

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%';

채권 금리

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

그리고 라틴어를 사용하여,

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%';

가 산출됩니다

물론
+------+ 
| id | 
+------+ 
| 1 | 
+------+

가, 영업 이익은 응용 프로그램 (PHP)에서 같은 캐릭터 세트가 있어야 연결 (MySQL은 리눅스 5.0에 latin1에하는 기본값으로 사용하지만, 기본적으로 5.1 UTF8로), 및 더 적은 미지수를 갖기 위해 필드 데이터 유형에서. Collations가 나머지를 처리합니다.

편집 : 내가해야모든 것을 통해 더 나은 제어 할 썼습니다 만, 다음도 작동합니다

연결 캐릭터 세트가 설정되면, MySQL은 내부적으로 변환을 수행, 때문에
set names latin1; 
select id from members where lastname like 'test6ë%';

. 이 경우에는 변환 된 UTF8 문자열 (DB에서)을 latin1 (쿼리에서)로 변환합니다.

편집 2 : 내가 더 무엇을했는지

여기, 문 위에 주어진 : 일부 회의적인 시각이 훨씬 더 설득력있는 예를 제공하기 위해 저를 필요로한다. 터미널이 UTF8인지 확인하십시오.

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);

members가 UTF8이고 members2가 라틴에 있음을 기억하십시오.

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

정확한 설정으로 증명되면 데이터 정렬이 도움이됩니다.

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

test 테이블은 다음과 같습니다 :

+0

@Danosaure - 사실이 아닙니다. '르네 (Renée)'는 UTF8이며, latin1 (iso-8859- *)이 아닙니다. – ajreal

+0

@ajreal : 번역되었습니다. 내가 게시하기 전에 그것을 테스트했습니다. 그에 따라 환경을 구성해야합니다 (터미널, 연결 및 데이터 정렬). 내가 틀렸다는 말을하기 전에 테스트 해 봤니? – Danosaure

+0

@Danosaure - 분명히 당신이 틀렸을 때 ... 당신의 방법은 문자가 모두 utf-8에 있다고 가정합니다. 이것은 사실이 아닙니다. 내 힌트는,'char_length'를 사용하십시오. – ajreal

4

먼저 오프,이 방식으로 작동한다

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

무엇 당신의 MySQL 버전이며, 어떻게 일을 일치하려고합니까? 다른 가능한 솔루션


하나 음역이다.

관련 : PHP Transliteration

문제가 안 음역을 입력하지만, 영구 저장 장치로부터 (예를 들어, 데시벨)을 음역 값을 검색하는 동안 실시간 불가능할 수있다. 따라서 username_slug, firstname_sluglastname_slug과 같은 세 개의 필드를 추가 할 수 있습니다. 레코드를 삽입/수정할 때 슬러그 값을 적절하게 설정하십시오.그리고 검색 할 때 슬러그 필드에 대해 음역 입력을 검색하십시오.

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

"renee"또는 "renèe"를 검색하면 모든 레코드가 일치합니다.

부작용으로 SEF (검색 엔진 친화적 인) 링크를 생성하는 데 해당 필드를 사용할 수 있으므로 ..._slug이라는 이름이 붙습니다. example.com/users/renee. 물론이 경우 슬러그 필드의 고유성을 확인해야합니다.

+0

처음에는 좋은 생각 일 수 있지만 이러한 유형의 설치는 업데이트 악몽입니다. ​​단단한 프레임 워크가 없으면 아무도 직접 데이터베이스를 직접 업데이트하지 않는 한 업데이트 악몽입니다. 데이터베이스에 보관하는 대신 실시간 음역을 선호합니다. – Danosaure

+0

일반적으로 성능이 저하되기 시작하면 일반적으로 표준화가 진행됩니다. :) –

관련 문제