Reputation: 13
So I have a little image gallery that I started to enhance using tags. I decided I go with simplest solution and I have a table just like:
describe photo_tags;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| photoid | bigint(20) | NO | PRI | NULL | |
| tag | varchar(32) | NO | PRI | NULL | |
+---------+-------------+------+-----+---------+-------+
It works, I have unique index for the photoid,tag pair to avoid duplicates and generally it does what's expected, spare for one annoying thing: I want to be able to search not just by a single tag, but a phrase.
The query (example below) is generated by PHP based on sanitized query string treated with str_word_count.
An example, here's a snippet from actual entries in 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 |
+---------+-----------------------+
Say I want to search the gallery based on tag "red truck":
This will not work, obviously
select photoid from photo_tags where tag="red truck" or (tag="red" and tag="truck");
This will sort of work:
select photoid from photo_tags where tag="red truck" or tag in('red','truck');
but it will basically select photoid that obviously have red or truck, not necessarily both of them.
Does anyone have idea how to improve the query so without modifying underlying table. Or maybe there's another way to achieve what I'm trying to do? I'm using MariaDB 10.3 and PHP 7.3 (basically what comes in Debian 10)
Upvotes: 1
Views: 41
Reputation: 1269513
I think you want aggregation:
select photoid
from photo_tags
where tag in ('red', 'truck')
group by photoid
having count(*) = 2;
If you can have 'red truck'
as well, then:
select photoid
from photo_tags
group by photoid
having sum(tag in ('red', 'truck')) = 2 or
sum(tag = 'red truck') > 0;
Upvotes: 2