Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php SQL匹配所有关键字的开头_Php_Mysql_Sql_Jquery Ui - Fatal编程技术网

Php SQL匹配所有关键字的开头

Php SQL匹配所有关键字的开头,php,mysql,sql,jquery-ui,Php,Mysql,Sql,Jquery Ui,我将设置一个场景,以最好地描述我试图实现的目标 有一个自动完成字段。自动完成功能适用于电视节目。用户输入“thewal”,希望找到“行尸走肉” 数据库: CREATE TABLE `shows` ( `id` int(10) unsigned NOT NULL, `name` varchar(250) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `tags` (

我将设置一个场景,以最好地描述我试图实现的目标

有一个自动完成字段。自动完成功能适用于电视节目。用户输入“thewal”,希望找到“行尸走肉”

数据库:

CREATE TABLE `shows` (
  `id` int(10) unsigned NOT NULL,
  `name` varchar(250) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `tags` (
  `tag` varchar(50) NOT NULL DEFAULT '',
  `sid` int(10) unsigned NOT NULL,
  KEY `sid` (`sid`),
  KEY `alphabetizer` (`tag`),
  CONSTRAINT `tags_ibfk_1` FOREIGN KEY (`sid`) REFERENCES `shows` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
其中,
shows
是所有电视节目的表格,
tags
是与每个电视节目相关联的所有标签的表格

每个节目标题中的每个单词都作为自己的小写标记插入到
标记
表中

显示的
表格中:

  • (身份证号码:1)(姓名:行尸走肉)
  • (身份证号码:2)(姓名:流浪企鹅)
标记
表中:

  • (sid:1)(标签:the)
  • (sid:1)(标签:步行)
  • (sid:1)(标签:死)
  • (sid:2)(标签:the)
  • (sid:2)(标签:漫游)
  • (sid:2)(标签:企鹅)
目标:用户输入“Wal”,用户得到:“行尸走肉”。查询应该返回满足条件的所有结果,而不仅仅是一个结果。因此,如果“活着行走”也是一个带有相应标签的节目,那么它也应该出现

我的问题:用户输入,“Wal”,用户获得两个节目。这是由于LIKE语句的OR子句造成的。我试了两天,不知道如何解决这个问题

我当前的查询:

SELECT name
    FROM shows s
    JOIN tags t ON s.id = t.sid
    WHERE t.tag LIKE "The%" OR t.tag LIKE "Wal%"

一种方法是使用
而不是
。但是,您需要使用聚合来获得您想要的:

SELECT name
FROM shows s JOIN
     tags t
     ON s.id = t.sid
WHERE t.tag LIKE 'The%' OR t.tag LIKE 'Wal%'
GROUP BY name
HAVING sum(t.tag LIKE 'The%') > 0 AND
       sum(t.tag LIKE 'Wal%') > 0;
然而,我认为这并不能解决您的问题,因为您不知道所有关键字都匹配。相反,请按匹配的关键字数排序,然后选择最匹配的关键字:

SELECT name
FROM shows s JOIN
     tags t
     ON s.id = t.sid
WHERE t.tag LIKE 'The%' or t.tag LIKE 'Wal%'
GROUP BY name
ORDER BY (MAX(t.tag LIKE 'The%') +
          MAX(t.tag LIKE 'Wal%')
         ) DESC
LIMIT 1;

运行此查询的另一种方法是为每个标记添加
EXISTS
语句。此查询可以利用
tag(sid,tag)


我不认为你的方法是正确的。但这里有一个正在发生的事情的解释

当您将
shows
加入到
标记
时,到目前为止匹配的每个单词都会返回一条记录

根据您的示例,使用

1. The Walking Dead
2. The Wandering Penguin
这个问题呢

SELECT *
FROM shows s
JOIN tags t ON s.id = t.sid
WHERE t.tag LIKE "the%" OR t.tag LIKE "wa%" /* note lower-case query */
你会得到结果的

ID  NAME                  TAG
 1  The Walking Dead      the
 1  The Walking Dead      walking
 2  The Wandering Penguin the
 2  The Wandering Penguin wandering
如果查询中有三个匹配的单词,则会看到不同的结果

问:佤邦死亡

会给

ID  NAME                  TAG
 1  The Walking Dead      the
 1  The Walking Dead      walking
 1  The Walking Dead      dead
 2  The Wandering Penguin the
 2  The Wandering Penguin wandering
您可以使用
groupby
消除重复项,并使用
COUNT(*)根据匹配的字数对结果进行评分

给予

你该怎么办
我认为这种索引方法从长远来看可能不会奏效。现代数据库为此具有内置功能。在这种情况下,当
标记
表达到数百万行并且
显示
标记
的连接变得无法管理时,使用DB的本机功能可能会为您节省大量的麻烦

我认为公认的答案过于复杂了。只需添加一个输入参数“tags\u count”并使用它:

SELECT sid
  FROM tags t 
  WHERE t.tag LIKE "The%" OR t.tag LIKE "Wal%"
  GROUP BY sid
  HAVING count(distinct tag) = 2;


因此,我们只查询包含所有指定标记的显示

使用
子句,而不是
子句@웃웃웃웃웃 这是行不通的。字段不能同时是两个值。但在您的表架构中,您显示的是添加了mysql标记,因为语法显然是mysql。@GordonLinoff谢谢,我以为我有。您好,第二个查询没有为我返回任何内容?@Graydams。为了得到正确的答案,我做了很多修改。看看当前的版本。如果有另一个名为“活着行走”的节目,那么由于限制器的原因,它不会与第二个查询一起出现。但是,移除限制器可能会返回太多的结果以及不完全相关或不完全匹配的结果。“自动完成”理想情况下不会只返回一个节目。@GrayAdams。最简单的事情是从第二个查询返回一些数字,不管您喜欢的限制是什么。我不明白为什么第一个查询不理想,因为它似乎返回了我想要的结果。你想详细说明一下吗?我想使用全文,但由于使用共享主机,我无法升级到5.6以便在InnoDB数据库上使用它。我需要InnoDB的外键。不幸的是,最终的查询返回与任何关键字匹配的所有显示,这是最初的问题。我知道MyISAM数据库中有用于此目的的本机函数,这可能意味着如果本机函数不存在(InnoDB),这是管理数据库的有效方法。@grayams如果您只想匹配所有关键字,可以使用have COUNT(*)=num_关键字或其他只需在其上下注并执行WHERE show.NAME,如“用户键入的内容%”,如果需要,您可能还可以创建一个单独的表,该表只有ID、名称,是
shows
的副本,是MyISAM表。这将使您在可以更新到>5.6之前保持不变,同时使您能够正确索引。我认为这可能比这个标签表更容易管理。您可以使用触发器将数据从
shows
复制到
shows\u index
(或您所称的任何内容)。你甚至可以在索引中添加其他字段,这样你的搜索就可以在不仅仅是标题上自动完成。这个解决方案也很有效。就性能而言,对于我拥有超过45000行的shows表,它似乎与Gordon的几乎相同。远程只需64毫秒。@grayams您是否在
标记(sid,标记)
上添加了复合索引?虽然我想你的速度不会超过64毫秒,但我没有。这样做之后,它似乎提高了性能,使这个查询快了几毫秒。第一次查询花费一些时间,第二次查询花费更少的时间,这有意义吗?显然也是这样。自动完成现在需要一秒钟的时间。编辑:与Gordon的解决方案相比,Gordon的解决方案花费的时间更少。如果第二个查询在运行您的查询后被MySQL缓存,那么它可能会花费更少的时间,它似乎会拉起所有标记
ID  NAME                  TAG
 1  The Walking Dead      the
 1  The Walking Dead      walking
 1  The Walking Dead      dead
 2  The Wandering Penguin the
 2  The Wandering Penguin wandering
SELECT s.name, COUNT(*)
FROM shows s
JOIN tags t ON s.id = t.sid
WHERE t.tag LIKE "the%" OR t.tag LIKE "wa%" OR t.tag LIKE "dead"
GROUP BY NAME
ORDER BY COUNT(*) DESC
 NAME                COUNT(*)
 The Walking Dead      3
 The Wandering Penguin 2
SELECT sid
  FROM tags t 
  WHERE t.tag LIKE "The%" OR t.tag LIKE "Wal%"
  GROUP BY sid
  HAVING count(distinct tag) = 2;