【问题标题】:mysql multi-column searchmysql多列搜索
【发布时间】:2009-02-10 09:24:23
【问题描述】:

我有一张这样的桌子:

+-------------------+---------------+
| description       | colour        |
+-------------------+---------------+
| Macrame Dress     | Washed Black  |
| Darcelle Gilet    | Dirty Shellac |
| Darcelle Cardigan | Washed Black  |
| Let It Rot Vest   | Optic White   |
| Let It Rot Crew   | Washed Black  |
| Let It Rot Crew   | Optic White   |
| Battalion Short   | Somme         |
| Seine Dress       | Washed Black  |
| Seine Dress       | Cocomotion    |
| Odette V-neck     | Linen Marl    |
+-------------------+---------------+
我想搜索“黑色连衣裙”,它只返回第 1 行和第 8 行。如果我输入“黑色”,它将返回第 1、3、5 和 8 行。连衣裙应该返回第 1、8 和 9 行。

谁能想到一个非常优雅、漂亮的 sql 语句,它可以接受任意数量的搜索词并返回最简洁的结果集。我能想到一些非常丑陋的方法来做到这一点,但它们破坏了我的业力。

【问题讨论】:

    标签: php mysql


    【解决方案1】:

    我能想到的唯一不错解决方案(因果报应)将涉及使用FULLTEXT 索引。这将允许您使用这样的查询:

    SELECT * FROM mytable
    WHERE MATCH (description,color) AGAINST ('black dress');
    

    不幸的是,如果我没记错的话,FULLTEXT 索引需要 MyISAM 表类型。

    编辑

    我怀疑这就是您要查找的内容,但让我添加它以供讨论。您可以将您的数据复制到一个临时 MyISAM 表中,然后在上面进行全文搜索:

    CREATE TEMPORARY TABLE mytmptable ENGINE=MyIsam SELECT * FROM mytable;
    ALTER TABLE mytmptable ADD FULLTEXT KEY (description,color); 
    SELECT * FROM mytmptable WHERE MATCH (description,color) AGAINST ('black dress');
    

    【讨论】:

    • 很遗憾,由于其他索引和事务限制,我无法更改引擎,但是是的,这将是我理想的解决方案。
    • 你知道你可以设置每个表使用的引擎,对吧?因此,如果您很幸运并且对 此特定表 没有事务约束,则可以将其设为 MyISAM 而不会影响其他表。 [PostgreSQL 的编辑插件]
    • 不,这个表必须是 innoDB,它是网站的主要产品表,所以必须是事务性的
    【解决方案2】:
    where colour+description like '%s1%'
    

    【讨论】:

    • 这就是我想出的解决方案,但我担心“水洗黑色花边连衣裙”与“黑色连衣裙”不匹配
    • 那么我们需要打破这两个搜索词并有:其中颜色+描述如'%s1%'和颜色+描述如'%s2%'
    • .. 当然不会使用索引,然后会进行全表扫描。
    【解决方案3】:

    您的列是什么数据类型?如果它们是 VARCHAR 或类似的,你只需做

    select 
      * 
    from 
      tbl 
    where 
      description like '%(s1)%' 
      or colour like '%(s1)%'
    

    (改编自@Pax,我认为他误解了这个问题——我认为它的意思是只要搜索词出现在“描述”或“颜色”中,它就应该匹配。)

    【讨论】:

    • 如果颜色像黑色或描述像连衣裙,这将返回结果,但我只需要返回黑色连衣裙。它是一个 AND,但超过 2 列。我计划在第二个查询中使用 OR 作为 UNION 的一部分作为后备
    【解决方案4】:

    理想情况下,我认为您应该有两个单独的搜索词,一个用于描述 (s1),一个用于颜色 (s2)。

    那么你的查询变成:

    select * from tbl where description like '%(s1)%' and colour like '%(s2)%'
    

    当然要代入 s1 和 s2 的值。

    空白 s2 会导致 %% 应该匹配所有内容(我认为)。

    为了能够在任一字段中搜索多个字词,您需要类似

    select * from tbl
        where description + colour like '%(s1)%'
          and description + colour like '%(s2)%'
          and description + colour like '%(s3)%'
    

    这必须根据搜索模式中的单词数量动态构建(因此“黑色连衣裙”将有 s1 和 s2,黑色只有 s1)。 “描述+颜色”位是连接字段;我的 SQL 有点生疏,所以我不知道你会怎么做,但这个概念是合理的。

    【讨论】:

    • 感谢 Pax,但我认为多个字段不适合简单的用户体验。我认为用户应该能够输入任何内容,并且代码应该围绕用户工作。你的多连接解决方​​案可以工作,这是我最初想出的,但我正在寻找更优雅的东西。
    • 没问题,斯图尔特,但你是一个很难取悦的人 :-) 由于你的约束很重(不允许对表格进行更改),这会阻碍所有可能的答案。您可能必须在您的约束和您想要的优雅之间做出选择,这取决于对您来说哪个更重要。
    【解决方案5】:

    好吧,只要你可以使用 PHP 来组装查询,这应该可以工作:

    SELECT * FROM tbl
    WHERE (description LIKE '%black%' OR colour LIKE '%black%')
    AND (description LIKE '%dress%' OR colour LIKE '%dress%')
    

    ...在其中为搜索词中的每个单词添加括号中的条件之一,并将它们与“AND”连接起来。这要求搜索词中的每个单词至少在其中一列中匹配。

    这不是纯 SQL(实际查询将取决于搜索词中有多少单词),但感觉合理优雅,我认为它应该可以完成这项工作。

    【讨论】:

      【解决方案6】:
      $node=explode(" ",$keysearch);
      $sql="SELECT * FROM tbl_dress WHERE ";
      $x=0;
      foreach ($node as $key => $ns) {
          $x++;
          if ($x > 1){$sql.=" AND ";}
          $sql.="(CONCAT(description, colour) LIKE '%$ns%')";
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-01-13
        • 1970-01-01
        • 1970-01-01
        • 2013-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多