以下查询会因@(符号)而导致错误。删除后,查询将正常工作。我试图逃避@角色,但没有运气。
SELECT * FROM clients WHERE MATCH (form) AGAINST ('test@test.com' IN BOOLEAN MODE);
产生的错误是:
#1064 - syntax error, unexpected '@', expecting $end
请注意,我正在phpMyAdmin SQL控制台区域中测试这些查询,因此我的其他编程不会出现转义错误。
MySQL服务器版本为5.6.17。
有什么想法吗?感谢。
答案 0 :(得分:11)
这与INNODB FULLTEXT索引相关联。
它是作为以下组合引入的:
InnoDB全文搜索不支持在单个搜索词上使用多个运算符
- 醇>
@距离 此运算符仅适用于InnoDB表。它测试两个或多个单词是否都在相互指定的距离内开始,用单词测量。
http://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html
# Running a test search for MATCH('+test{$ascii}test' IN BOOLEAN MODE) on all ASCII chars returns errors on:
40 (
41 )
64 @
MYSQL似乎将这些符号视为wordbreaks并且我发现无法逃脱并将其包含在实际查询中,因此我的解决方案是对符号进行拆分并将它们作为一个组包含在内。 “test @ bar”==(+ test + bar)
# As a further test, running a search for MATCH('+{$ascii}' IN BOOLEAN MODE) returns errors for:
40 (
41 )
42 *
43 +
45 -
60 <
62 >
64 @
126 ~
这与MYSQL文档中的预期一样,是特殊的BOOLEAN修饰符
# As a testcase (Requires MYSQL 5.6+):
CREATE TABLE `fulltext_innodb` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text` text COLLATE utf8_unicode_ci,
PRIMARY KEY (`id`),
FULLTEXT KEY `text` (`text`)
) ENGINE=InnoDB
INSERT INTO `fulltext_innodb` (`id`, `text`) VALUES (1, 'test@bar');
SELECT * FROM `fulltext_innodb` WHERE MATCH (`text`) AGAINST( '+test@bar’ IN BOOLEAN MODE )
#1064 - syntax error, unexpected '@', expecting $end
答案 1 :(得分:0)
似乎没有办法用任何其他字符替换“ @”。到目前为止,发现“ @”并在搜索后添加字符串是最好的解决方法。 这意味着
$mail = 'test@test.com';
$mail = str_replace("@", " +", $mail); //replace the @ that causes the problem
$query = "SELECT * FROM clients WHERE MATCH (form) AGAINST ('$mail' IN BOOLEAN MODE)'; //query with replaced mail address
应该带来所需的结果。
另一种方法是像在this post中那样处理它,它包含一个类似的问题,但又有一个很好的解决方法。
答案 2 :(得分:0)
不是直接的答案,但是如果有人在寻找PHP代码来处理用户输入的搜索字符串以进行全文搜索的标记化,则可以使用以下代码:
/**
* Method to take an input string and tokenize it into an array of words for Full Text Searching (FTS).
*
* This method is used when an input string can be made up of multiple words (let's say, separated by space characters),
* and we need to use different Boolean operators on each of the words. The tokenizing process is similar to extraction
* of words by FTS parser in MySQL. The operators used for matching in Boolean condition are removed from the input $phrase.
* These characters as of latest version of MySQL (8+) are: +-><()~*:""&|@ (@ is specific for InnoDB)
* We can also execute the following query to get updated list: show variables like 'ft_boolean_syntax';
* Afterwards, the modified string is split into individual words considering either space, comma, and, period (.) characters.
* Details at: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html
*
* @param string $phrase Input statement/phrase consisting of words
* @return array Tokenized words
* @author Madhur, 2019
*/
function tokenizeStringIntoFTSWords(string $phrase) : array {
$phrase_mod = trim(preg_replace('/[><()~*:"&|@+-]/', ' ', trim($phrase)));
$words_arr = preg_split('/[\s,.]/', $phrase_mod, null, PREG_SPLIT_NO_EMPTY);
// filter out the fulltext stop words and words whose length is less than 3.
$fts_words = array();
$fulltext_stop_words = array(
'about','are','com','for','from','how','that','this','was','what',
'when','where','who','will','with','und','the','www'
);
foreach($words_arr as $word) {
// By default MySQL FULLTEXT index does not store words whose length is less than 3.
// Check innodb_ft_min_token_size Ref: https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_ft_min_token_size
// So we need to ignore words whose length is less than 3.
if(strlen($word) < 3) continue;
// Ignore the fulltext stop words, whose length is greater than 3 or equal to 3.
// Ref: https://dev.mysql.com/doc/refman/8.0/en/fulltext-stopwords.html
if (in_array($word, $fulltext_stop_words)) continue;
$fts_words[] = $word;
}
return $fts_words;
}
以上代码将处理停用词,最小字长限制以及布尔模式运算符。因此,例如,如果用户输入:Search@bar with in Javascript
,它将返回(Search, bar, Javascript)
的数组。然后,可以使用此数组编写全文查询。