SQL 根据多行列中的数据查询到 select 结果 - 基于标签的词组搜索

SQL query to select result based on data from column in multiple rows - phrase search based on tags

所以我有一个小图片库,我开始使用标签来增强它。我决定采用最简单的解决方案,我有一个 table 就像:

describe photo_tags;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| photoid | bigint(20)  | NO   | PRI | NULL    |       |
| tag     | varchar(32) | NO   | PRI | NULL    |       |
+---------+-------------+------+-----+---------+-------+

它有效,我有 photoid 的唯一索引,标签对避免重复,通常它会做预期的事情,但有一件烦人的事:我希望能够不仅通过单个标签进行搜索,而且能够通过一个标签进行搜索短语。

查询(下面的示例)由 PHP 基于使用 str_word_count 处理过的经过清理的查询字符串生成。

举个例子,这里是 DB 中实际条目的片段

+---------+-----------------------+
| photoid | tag                   |
+---------+-----------------------+
|    8717 | red                   |
|    8717 | road                  |
|    8717 | sky                   |
|    8717 | tanker                |
|    8717 | trees                 |
|    8717 | truck                 |
|    8717 | truck on truck action |
|    8717 | vehicle               |
|   18858 | clouds                |
|   18858 | green                 |
|   18858 | park                  |
|   18858 | sky                   |
|   18858 | trees                 |
|   18858 | truck                 |
|   18858 | vehicle               |
|   18858 | walkway               |
+---------+-----------------------+

假设我想根据标签“红色卡车”搜索图库:

这显然行不通

select photoid from photo_tags where tag="red truck" or (tag="red" and tag="truck");

这将有点工作:

select photoid from photo_tags where tag="red truck" or tag in('red','truck');

但它基本上会 select 明显有红色或卡车的 photoid,不一定两者都有。

有没有人知道如何在不修改底层 table 的情况下改进查询。或者也许还有另一种方法可以实现我想要做的事情?我正在使用 MariaDB 10.3 和 PHP 7.3(基本上是 Debian 10 中的版本)

我想你想要聚合:

select photoid
from photo_tags 
where tag in ('red', 'truck')
group by photoid
having count(*) = 2;

如果你也能有'red truck',那么:

select photoid
from photo_tags 
group by photoid
having sum(tag in ('red', 'truck')) = 2 or
       sum(tag = 'red truck') > 0;