在MySQL中搜索多个列以获得自动完成结果

3
我正在使用以下代码和Jquery自动完成功能来填充我的网站上的搜索建议...
$results = mysql_query('SELECT DISTINCT artist FROM mm_albums WHERE artist LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" ORDER BY artist ASC LIMIT 0,10', $dbcon);

$data = array();
if ( $results && mysql_num_rows($results) )
{
while( $row = mysql_fetch_array($results, MYSQL_ASSOC) )
{
    $data[] = array(
        'label' => $row['artist'],
        'value' => $row['artist']
    );
}
}

echo json_encode($data);
flush();

这个功能可以正常运行,但我希望能够跨多列搜索各种结果,例如:

  • 来自艺术家列的艺术家名称

  • 来自名称列的曲目名称

  • 来自标签列的唱片公司名称

我刚刚花了两个小时阅读大量不同的方法,但没有一个完全适合我想要做的事情,而且我在格式化查询时遇到了麻烦。

有人有什么建议吗?

--以下是编辑后添加的解决方案--

这是我如何通过 Ed 的建议让它正常工作的,以防其他人也在尝试这样做。

这将从 2 个不同的表中搜索 4 个不同的列,并将用户键入的搜索词与其中任何列中找到的任何内容匹配,同时剥离重复的结果。 这在JQuery Autocomplete中无缝运行,以下是设置方法。

1)创建以下 php 文件并将其命名为search.php

<?php
if ( !isset($_REQUEST['term']) )
exit;

$connect = mysql_connect('dbhost', 'dbusername', 'dbpassword') or die( mysql_error() );
mysql_select_db('dbname');

$results = mysql_query('SELECT artist AS shout FROM albums WHERE artist LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" UNION SELECT name FROM albums WHERE name LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" UNION SELECT label FROM albums WHERE label LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" UNION SELECT track_name FROM tracks WHERE track_name LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" ORDER BY 1 LIMIT 10', $connect);

$data = array();
if ( $results && mysql_num_rows($results) )
{
while( $row = mysql_fetch_array($results, MYSQL_ASSOC) )
{
    $data[] = array(
        'label' => $row['shout'],
        'value' => $row['shout']
    );
}
}

echo json_encode($data);
flush();
?>

2) 在您的新脚本中,用实际用于连接到数据库的详细信息替换 dbhostdbusernamedbpassworddbname尽管我建议您不要将这些信息存储在此文件中。更好的方法是将连接信息存储在单独的文件中,在 web 根目录之外查找它,并在此处使用 `include' 引用它

3) 用您自己的查询替换它们。这是我的设置方式,因此您可以看到需要替换的内容...

首先,将搜索字符串重命名为 shout(仅为了清晰),然后在表 albums 中搜索列 artist,并将 artist 与 Autocomplete 生成的搜索 term 进行匹配。

此格式重复搜索以下内容...

albums 中的 name albums 中的 label tracks 中的 track_name

只需将此信息替换为您希望搜索的列和表,保存该文件并上传它。

4) 将以下搜索表单添加到页面中,其中 pathtoyoursearchenginescript.php 指向您的搜索引擎。

<form action="pathtoyoursearchenginescript.php" method="post">
Search: <input type="text" id="suggest" /> <input type="submit" value="Search" />
</form>

假设您在页面上已经加载了所需的.js库,那么您只需要将这一小段代码添加在任何位置即可完成!

<script type="text/javascript">
jQuery(document).ready(function($){
$('#suggest').autocomplete({source:'search.php', minLength:2});
});</script>

注意:以上代码假设search.php位于您的Web根目录中,如果不是,请确保使用正确的文件位置进行更新。
希望这对某些人有用;)

请勿在新代码中使用 mysql_* 函数。你应该考虑使用 mysqli 或 PDO,这是有很好的理由的。更多详情请参见此处:https://dev59.com/3Gcs5IYBdhLWcg3wcDaZ - jcsanyi
是的,我知道,我也有这个脚本的PDO版本,但旧的方式更易于阅读和理解。我不知道为什么他们会废弃旧代码,因为使用PDO编写完全相同的函数几乎要长两倍! - Grant
mysqli_ 函数可以以几乎与 mysql_ 函数完全相同的方式使用。只是当您以这种方式使用它时,它不提供与绑定参数相同的保护级别 - 但至少它不是一个不受支持的库。 - jcsanyi
是的,非常正确。但我有一个完整的老式电子商务网站,我暂时不想重新编写它 ;) - Grant
3个回答

1
我会为此使用UNIONUNION将删除重复值,因此您不需要使用DISTINCT关键字:
SELECT artist FROM mm_albums WHERE artist LIKE <value>
UNION SELECT name FROM mm_albums WHERE name LIKE <value>
UNION SELECT label FROM mm_albums WHERE label LIKE <value>
ORDER BY 1 LIMIT 10

这将从“艺术家”、“名称”和“标签”列中提取关键词。

我会尝试这种方法,但我需要如何修改我的数组输出? - Grant
你不需要这样做。该列仍将命名为 artist,因为这是第一个 SELECT 语句中的名称。我知道现在这很令人误解,因为该列可能有艺术家、名称或标签,所以如果您希望可以在第一个 SELECT 中分配一个更合适的名称,例如: SELECT artist AS searchvalue FROM ...,然后继续进行查询的其余部分。如果您这样做,那么您将想把数组称为 $row['searchvalue']。不过这取决于您,选择您最舒适的方式。 - Ed Gibbs
太棒了,完美地解决了!非常感谢您的帮助,并以易于理解的方式进行解释。干杯! - Grant

0
$results = mysql_query('SELECT DISTINCT artist FROM mm_albums WHERE artist LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" or name LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" or label LIKE "'. mysql_real_escape_string($_REQUEST['term']) .'%" ORDER BY artist ASC LIMIT 0,10', $dbcon);

0

像这样的代码可以满足你的需求:

$results = mysql_query('SELECT DISTINCT artist FROM mm_albums WHERE artist LIKE "%'.
  mysql_real_escape_string($_REQUEST['artist']) .'%" OR name LIKE "%'.
  mysql_real_escape_string($_REQUEST['track']) .'%" OR label LIKE "%'.
  mysql_real_escape_string($_REQUEST['label']) .'%" ORDER BY artist ASC LIMIT 0,10', $dbcon);

你还需要在请求中传回更多的参数 - 在这种情况下是三个,每个值都需要一个参数来查询。


尝试这种方式...几个问题..1)请求每次必须是“term”(而不是艺术家,曲目,标签),因为这就是自动完成发送的内容。可以吗?2)我应该在$row数组中放什么?目前只使用了艺术家结果,但显然需要扫描所有三个。 - Grant
你能编辑你的问题并添加发出请求的客户端JS吗?这会很有帮助。 - Duncan Lock
如果你想在这三个字段中搜索相同的字符串,可以使用 term 代替 artisttracklabel - Duncan Lock
没关系,邓肯。我已经按照艾德上面的方法做到了,并且它完美地运行。不过还是谢谢你的帮助。 - Grant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接