PHP/MYSQL -布尔全文搜索-精确字符串运算符("")在准备语句和SQL查询中给出不同的结果集


PHP/MYSQL - Boolean Full-Text Searches - exact string operator ("") gives different result sets in Prepared Statement vs SQL Query

我在我的网站上使用PHP准备语句查询MySQL数据库MyISAM表使用布尔全文搜索的高级搜索页面。

它与Google提供的高级搜索的第一部分非常相似,涵盖了以下条件:

  • 所有这些字
  • 确切的单词或声明(注意:这就是问题所在)

我检索每个输入值,清理和处理字符串集合的每个部分,然后附加适当的信息,通过准备好的语句形成mySQL查询。

所以对于下面的搜索:

  • ——
  • 准确——
  • 任意-希捷东芝
  • 没有——

将输出如下字符串:

seagate* toshiba*

查询的结果会像这样:

SELECT id, description
FROM `items` 
WHERE MATCH (description)
AGAINST ('seagate* toshiba*' IN BOOLEAN MODE)

它将列出所有带有"seagate"字样的行。后面跟着anything和toshiba"后面是描述字段中的任何内容。

这很好,输出

也是如此:
-(750gb*) -(320gb*) seagate* toshiba*

将像上面那样列出所有行,但不包括任何带有"750gb"answers"320 gb"

通过在"字符串,我们将得到如下输出:

+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) seagate* toshiba*

将像上面那样列出所有行,但只显示包含"16mb"answers"7200 rpm"

现在是问题部分。如果我要使用"陈述的确切词"字符串并添加值"serial ata 600"我们将得到如下输出:

+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) +("serial ata 600") seagate* toshiba*

使用phpmyadmin将此字符串和结果查询作为sql查询运行,我得到匹配搜索条件的2行结果集。

然而,当在我的网站上运行这个时,我得到6行的结果,这将表明+("serial ata 600")"被完全忽略了

如果我只输入字符串"所以我们得到的输出是:

+("serial ata 600")

结果将表明此字符串将列出包含"serial"或";ata"或"600"。

通过直接在mysql中运行相同的查询,该结果将列出恰好包含单词"serial ata 600"的所有行。

这个操作符的MySQL定义是:

A phrase that is enclosed within double quote (“"”) characters matches 
only rows that contain the phrase literally, as it was typed.

这是MySQL中的情况,但是当在PHP中运行相同的查询时,作为Prepared Statement返回不同的结果集。

下面是准备好的语句:

if ($result = $link->prepare("
    SELECT id, description
    FROM `items` 
    WHERE MATCH (description)
    AGAINST (? IN BOOLEAN MODE)
"))
{
    $result->bind_param("s", $pattern);
    ... ETC
}

下面是$pattern在此之前的输出:

+("serial ata 600")

有没有人可能会建议这种行为的原因,因为我没有看到任何理由在PHP和MySQL之间的工作方式有任何差异。

我可以提供有关如何根据请求生成字符串的任何附加代码,但输出与我的示例一样。

任何建议/建议/输入/反馈或评论都将非常感谢。

这是准备好的语句失败的地方。在内部,准备引擎将执行如下操作:

$quoted = mysql_real_escape_string('+("serial ata 600")');

相当于

+('"serial ata 600'")

现在你不再使用3个单词的引用短语了,你发送了以下单独的单词:

+("serial
ata
600")

这是因为"引号是SQL元字符,您需要将它们视为元字符。但是,因为它们是元字符,所以预处理引擎会引用它们,将它们简化为普通的简引号,现在它们不再包含搜索短语。它们已经成为搜索短语的一部分。

不知道这是否真的有效,但是你可能不得不重写准备好的语句,使其更像

... MATCH AGAINST (CONCAT('("', ?, '")'))