我将设置一个场景来最好地描述我想要完成的任务。
有一个自动填充字段。自动完成功能适用于电视节目。用户输入“The Wal”希望找到“行尸走肉”。
数据库:
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
是与每个电视节目相关的所有标签的表格。
每个节目标题中的每个单词都作为自己的小写标记插入tags
表中。
在shows
表中:
在tags
表中:
目标:用户输入“The Wal”,用户获取:“行尸走肉”。查询应返回符合条件的所有结果,而不仅仅是一个。因此,如果“The Walking Alive”也是带有相应标签的节目,它也应该出现。
我的问题:用户输入“The Wal”,用户获得两个节目。这是由LIKE语句的OR子句引起的。尝试2天后,我不知道如何解决这个问题。
我当前的查询:
SELECT name
FROM shows s
JOIN tags t ON s.id = t.sid
WHERE t.tag LIKE "The%" OR t.tag LIKE "Wal%"
答案 0 :(得分:1)
一种方法是使用and
代替or
。但是,您需要使用聚合来获得所需内容:
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;
答案 1 :(得分:0)
运行此查询的另一种方法是为每个标记添加EXISTS
语句。此查询可以利用tag(sid,tag)
SELECT name
FROM shows s
WHERE EXISTS (
SELECT 1 FROM tags t
WHERE t.sid = s.id
AND tag LIKE 'The%'
) AND EXISTS (
SELECT 1 FROM tags t
WHERE t.sid = s.id
AND tag LIKE 'Wal%'
)
答案 2 :(得分:0)
我不认为你的方法是合理的。但这里是对正在发生的事情的解释。
当您加入shows
到tags
时,您会为到目前为止匹配的每个字词获得一条记录。
根据您的示例,使用
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
如果您的查询中有三个匹配的单词,则会看到不同的结果
查询:Wa Dead
SELECT *
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"
会给出
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
您可以使用GROUP BY
消除重复项,并使用COUNT(*)
匹配的字词数对结果进行评分
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
我认为从长远来看,这种索引方法可能不会很好。现代数据库具有内置功能。 Here is a link to MySQL's full-text index feature。这种情况下,当tags
表达到数百万行并且shows
到tags
的JOIN变得无法管理时,使用数据库的本机功能可能会让您无后顾之忧。 。
答案 3 :(得分:0)
我认为接受的答案过于复杂。只需添加输入参数" tags_count"并使用它:
SELECT sid
FROM tags t
WHERE t.tag LIKE "The%" OR t.tag LIKE "Wal%"
GROUP BY sid
HAVING count(distinct tag) = 2;
因此我们只查询包含所有指定标签的节目