Where语句用于选择具有特定标记的记录

时间:2014-02-20 21:04:14

标签: php mysql sql

我的表看起来像这样:

id | title         | tags
1  | I like things | 9,3,7,10
2  | Stuff about i | 12,3,7,10
3  | Overly loaded | 1,3,4,5
4  | Never ever AT | 12,10
4  | Forever alone | 9

注意:这些名称已经完成,它们仅用于说明目的

关于标签的事情:

  • 数字代表给定标记的数字ID,范围从012
  • 1912将始终是此列表中的第一个标记,其后是从低到高的排序顺序的其余标记
  • 条目也只能包含一个标记,1912

我想添加一个过滤器功能,允许用户使用这些标签过滤列表。让我们忽略客户端部分,只关心我们收到的内容。

假设脚本收到以下输入(始终排序):"3,4,9"

然后,我想将此传递给MySQL查询以检索匹配的项目。该网站也有一个分页功能,但我只是这样说,因为它可能会影响语句的顺序,否则它并不重要。它只是在最后添加了LIMIT语句。

放弃所有转义和不放弃的内容,我尝试使用的查询是

SELECT * FROM `$tablename` WHERE tags LIKE '%$input%' ORDER BY title ASC LIMIT 0,10

但这 - 当然 - 没有用。我给了我这个不错的小错误信息,说:

  

您的SQL语法有错误;检查与MySQL服务器版本对应的手册,以便在 script.php 的第1行''%3,4,9%'附近使用ORDER BY标题ASC LIMIT 0,10'附近使用正确的语法在线 n

我想知道如何更改此查询以便能够正确过滤结果,即使它需要额外的功能来将多个LIKE语句附加在一起。

2 个答案:

答案 0 :(得分:3)

WHERE tags LIKE '%$input%'

仅在标签字符串中找到输入标签列表时才有效。 “3,4,9”不像“3,4,5,9”

你有一个非规范化的结构,这会导致你的问题,你应该实现每个标签值一行。

另一种方法是拆分输入字符串并使用多个OR LIKE语句:

WHERE tags LIKE '%input1%'
   OR tags LIKE '%input2%'
    ....

然后你必须处理111匹配的问题,这意味着在LIKE语句的每一侧的正面和背面连接逗号,或者填充一些值。解决方法变成了一个丑陋的野兽,其效率远低于修复底层设计问题。

答案 1 :(得分:2)

我知道这不会是公认的答案,但是因为可能会出现无法改变数据库结构的情况,我想我会把它作为问题的精确答案。

考虑到你所说的限制,假设PHP是你的控制语言(因为这个问题是用PHP标记的),我会用PHP构建SQL语句:

<?php
// assuming $tags contains your comma-delimited tags
$tags_array = explode(',',$tags);
$where = 'where true';
for($i=0;$i<sizeof($tags_array);$i++) {
  switch($tags_array[$i]) {
    case '1':
      $where .= " and tags LIKE '1%' and tags NOT LIKE '12%'";
      break;
    case '9':
    case '12':
      $where .= " and tags LIKE '" . $tags_array[$i] . "%'";
      break;
    default:
      $where .= " and tags LIKE '%," . $tags_array[$i] . "%'";
      break;
  }
}
$sql = "SELECT * FROM `$tablename` " . $where . " ORDER BY title ASC LIMIT 0,10";
?>

话虽如此,我同意上面评论的每个人:在数据库中正确地获取数据模型要好得多。