将文本与行匹配

时间:2009-08-14 15:29:22

标签: php mysql

我的mysql表中有一行像这样

John - Hey (johnnny)

但由于字符串的格式如何,我有

john hey johnnny

我试过这个查询

$q  = mysqli_query($id,"SELECT * FROM mixes WHERE `tracklist` LIKE %".$_REQUEST['did']."%");

但这不起作用?有什么想法吗?

5 个答案:

答案 0 :(得分:2)

不要完全按照这个问题而且我是Postgres的人,但我最好的猜测是你需要将参数包装在引号中。

$q  = mysqli_query($id,"SELECT * FROM mixes WHERE `tracklist` LIKE '%{$_REQUEST['did']}%'");

答案 1 :(得分:1)

您可能想要查看MySQL中的full text indexes/search。我认为自然语言模式应该能够找到搜索字符串的结果,而不管单词顺序,标点符号等。

请注意,这仅适用于MyISAM表。

答案 2 :(得分:1)

您需要将like参数包装在'中。您有以下内容:

$q  = mysqli_query($id,"SELECT * FROM mixes WHERE `tracklist` LIKE %".$_REQUEST['did']."%");

应该是:

$q  = mysqli_query($id,"SELECT * FROM mixes WHERE `tracklist` LIKE '% ".$_REQUEST['did']."%'");

请注意我放在第一个和最后一个%

前面的两个撇号

修改

因此,如果您在数据库中获得输入john hey johnnny' and your looking for John - Hey(johnnny)`,那么您将不得不操纵您正在搜索的字符串

$search = str_replace(" ", "%", $_REQUEST['did']); // john%hey%johnnny

$query = "SELECT * FROM mixes WHERE `tracklist` LIKE '".$search."'";
$q  = mysqli_query($id, $query);

%将匹配您需要的空格或字符。这与结尾)不匹配。但如果足够好,它会选择行。您可以在%变量之前和之后添加$search以匹配结尾)和/或您要查找的字符串之前的任何字符。

答案 3 :(得分:0)

有些选择是:

  1. 编写一个删除非字母数字和空格的函数,并将其应用于搜索查询中的列tracklist。一个很大的缺点是你的查询将无法使用tracklist上的任何索引。
  2. 使用某种形式的模糊匹配。这也很可能不会利用指数。有Tom Haigh的建议,它会在你的例子中找到这一行,但也可能会返回误报。您也可以使用REGEXP/RLIKE,它不执行模糊匹配,但您可以构造一个表达式:

    $tracklist=preg_replace('/[^a-z]+/i', '[^[=a=]]+', $_REQUEST['did']);
    $q  = mysqli_query($id,"SELECT * FROM `mixes` WHERE `tracklist` REGEXP '$tracklist'");
    

    使用'johnny hey johnnny'的示例$_REQUEST['did'],得到的查询是“SELECT * FROM mixes WHERE tracklist REGEXP'john [^ [= a =]] + hey [^ [=一个=]] + johnnny'”。以上忽略了非字母字符。如果要忽略非字母数字字符,请尝试以下操作之一(第二个不忽略'_'):

    $tracklist=preg_replace('/[^a-z0-9]+/i', '[^[:alnum:]]+', $_REQUEST['did']);
    
    $tracklist=preg_replace('/\W+/', '[^[:alnum:]_]+', $_REQUEST['did']);
    
  3. 重组表和处理逻辑。这是最多的工作,但将产生概念上最干净的实现。我猜测tracklist是$ delim(例如逗号,分号,...)分隔的曲目名称列表。如果是,则mixes甚至不是first normal form。创建一个新的tracklist表:

    CREATE TABLE `tracklist` (
        mix INTEGER REFERENCES mixes (id),
        position INTEGER NOT NULL,
        track INTEGER REFERENCES tracks (id),
        PRIMARY KEY (mix, position),
        KEY (mix, track),
        KEY (track)
    ) ENGINE=InnoDB;
    

    要查找给定曲目的混音,请执行连接:

    SELECT mixes.* FROM mixes 
        JOIN tracklist 
            ON mixes.id = tracklist.mix 
        WHERE tracklist.track=$trackid
    

    通过使用索引,上述查询将比其他两个选项更快。这种方法的主要缺点是你必须执行更多查询才能获得混合的跟踪列表。一个好处是它可以改善曲目列表编辑。通过适当定义的索引,此选项仍然可以比当前的数据库设计更快。例如,

    SELECT t2.mix, t2.position, tracks.*
        FROM tracklist AS t1 
        JOIN tracklist AS t2 
          ON t1.mix = t2.mix 
        JOIN tracks
          ON t2.track = tracks.id
        WHERE t1.track=:trackid
    
    如果tracklist.trackstracklist.mixtracks.id上有索引,那么

    会非常有效,这是一个非常合理的假设,给定tracklist的上述定义{ {1}}很可能是主键列。 MySQL只需要检查track.id。如果有两个混音包含“Johnny,Hey(johnnny)”,分别有8个和10个曲目,MySQL将检查总共38行(来自(number of mixes containing track :trackid) + (total number of tracks in all mixes that contain :trackid) * 2 rows的20行和来自tracklist的18行)。选项1和2需要检查tracks行。只要混音的数量远远大于平均混音大小,并且您正在寻找的音轨不会出现在许多混音中,这个选项比其他两个更快。

  4. 请注意,除非您在构建查询之前清理(number of mixes),否则您的脚本将向SQL injection[2][3])开放。选项2中使用$_REQUEST['did']的上述示例是安全的(清理是REGEXP的副作用),但最安全,最通用的方法是使用prepared queries

    preg_replace

    您还可以重复使用准备好的查询,这意味着数据库不需要重新分析查询,从而提高了速度。

        $q = mysqli_prepare($id,"SELECT * FROM `mixes` WHERE `tracklist` REGEXP ?");
        $q->bind_param('s', $_REQUEST['did']);
        $q->execute();
    

    请注意, function findMixFor($track) { global $id; static $q = Null; if (is_null($q)) { $q = mysqli_prepare($id,"SELECT * FROM `mixes` WHERE `tracklist` REGEXP ?"); } $q->bind_param('s', $track); $q->execute(); return $q; } 只是为了说明重用已准备好的查询。正确的实现将隔离数据访问层中的所有数据库访问,并处理错误。

    您可能还希望使用PDO而不是mysqli。首先,它对准备好的查询的支持更加丰富。另一方面,它可以轻松切换数据库。

答案 4 :(得分:0)

还有一个更广泛的问题 - 为什么你要尝试匹配这个问题以及你要解决的问题是什么?

我认为你的问题更深层次 - 你没有解决正确的问题。你真的想做什么?