Протестировал на выборке ~100.000 фраз, результат мне показался приемлимым. Если что не так отпишитесь, писал быстро, вполне возможно, что-то пропустил/упустил/не протестил. Спасибо.
PHP:
CREATE FUNCTION `METAPHONE`(Phrase VARCHAR(1000), Length INT) RETURNS varchar(400) CHARSET utf8
NO SQL
DETERMINISTIC
BEGIN
DECLARE it int;
DECLARE Chr CHAR;
DECLARE Letter CHAR;
DECLARE Result VARCHAR(400);
SET it=1;
SET Letter='';
SET Phrase=UPPER(Phrase);
SET Result='';
while it<=LENGTH(Phrase) AND LENGTH(Result)<Length do
SET Chr = MID(Phrase,it,1);
IF Letter='' AND LOCATE(Chr,'ABCDEFGHIJKLMNOPQRSTUVWXYZАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ') THEN
SET Letter = Chr;
END IF;
IF Chr='B' OR Chr='P' OR Chr='Б' OR Chr='П' THEN
SET Result = CONCAT(Result,'1');
ELSEIF Chr='F' OR Chr='V' OR Chr='Ф' OR Chr='В' THEN
SET Result = CONCAT(Result,'2');
ELSEIF Chr='C' OR Chr='K' OR Chr='S' OR Chr='С' OR Chr='З' OR Chr='Ц' THEN
SET Result = CONCAT(Result,'3');
ELSEIF Chr='G' OR Chr='J' OR Chr='Г' OR Chr='К' OR Chr='Х' THEN
SET Result = CONCAT(Result,'4');
ELSEIF Chr='Q' OR Chr='X' OR Chr='Z' OR Chr='Ж' OR Chr='Ш' OR Chr='Щ' OR Chr='Ч' THEN
SET Result = CONCAT(Result,'5');
ELSEIF Chr='D' OR Chr='T' OR Chr='Д' OR Chr='Т' THEN
SET Result = CONCAT(Result,'6');
ELSEIF Chr='L' OR Chr='Л' THEN
SET Result = CONCAT(Result,'7');
ELSEIF Chr='M' OR Chr='N' OR Chr='М' OR Chr='Н' THEN
SET Result = CONCAT(Result,'8');
ELSEIF Chr='R' OR Chr='Р' THEN
SET Result = CONCAT(Result,'9');
ELSEIF Chr='О' OR Chr='Ы' OR Chr='А' OR Chr='Я' THEN #А
SET Result = CONCAT(Result,'@');
ELSEIF Chr='Ю' OR Chr='У' THEN #У
SET Result = CONCAT(Result,'#');
ELSEIF Chr='Е' OR Chr='Ё' OR Chr='Э' OR Chr='И' OR Chr='Й' THEN #И
SET Result = CONCAT(Result,'$');
END IF;
SET it = it+1;
END WHILE;
RETURN CONCAT(Letter,IF(LENGTH(Result)<Length,RPAD(Result,Length-LENGTH(Result),'0'),Result));
END