Вы можете использовать справочную таблицу (также называемую таблицей сопоставления вместе со множеством других имен), чтобы разрешить связь «многие-многие» между тегами (одна таблица для всех) и объектами (снова одна таблица).
Таким образом, у вас есть таблица objects , каждый объект имеет id , и у вас снова есть таблица tags с id для каждого объект. Так что-то вроде: -
DROP TABLE IF EXISTS object_table;
CREATE TABLE IF NOT EXISTS object_table (id INTEGER PRIMARY KEY, object_name);
DROP TABLE IF EXISTS tag_table;
CREATE TABLE IF NOT EXISTS tag_table (id INTEGER PRIMARY KEY, tag_name);
Вы бы заполнили оба, например
INSERT INTO object_table (object_name) VALUES
('Object1'),('Object2'),('Object3'),('Object4');
INSERT INTO tag_table (tag_name) VALUES
('Apple'),('Orange'),('Grape'),('Pineapple'),('Melon'),
('London'),('New York'),('Paris'),
('Red'),('Green'),('Blue'); -- and so on
Таблица сопоставления будет выглядеть примерно так: -
DROP TABLE IF EXISTS object_tag_mapping;
CREATE TABLE IF NOT EXISTS object_tag_mapping (object_reference INTEGER, tag_reference INTEGER);
Сверхурочное время, поскольку теги присваиваются объектам или наоборот, вы добавляете сопоставления, например, : -
INSERT INTO object_tag_mapping VALUES
(1,4), -- obj1 has tag Pineapple
(1,1), -- obj1 has Apple
(1,8), -- obj1 has Paris
(1,10), -- obj1 has green
(4,1),(4,3),(4,11), -- some tags for object 4
(2,8),(2,7),(2,4), -- some tags for object 2
(3,1),(3,2),(3,3),(3,4),(3,5),(3,6),(3,7),(3,8),(3,9),(3,10),(3,11); -- all tags for object 3
После этого у вас могут появиться такие запросы: -
SELECT object_name,
group_concat(tag_name,' ~ ') AS tags_for_this_object
FROM object_tag_mapping
JOIN object_table ON object_reference = object_table.id
JOIN tag_table ON tag_reference = tag_table.id
GROUP BY object_name
;
- group_concat - агрегатная функция (применяется для GROUP), которая объединяет все значения, найденные для указанного столбца, с (необязательным) разделителем.
Результат запроса: -
Следующим может быть поиск, основанный на тегах (не то, чтобы вы вероятно использовали и tag_name, и tag_reference): -
SELECT object_name, tag_name
FROM object_tag_mapping
JOIN object_table ON object_reference = object_table.id
JOIN tag_table ON tag_reference = tag_table.id
WHERE tag_name = 'Pineapple' OR tag_reference = 9
;
Это приведет к: -
- Обратите внимание, что это простой обзор, например Вы можете рассмотреть возможность использования таблицы сопоставления в качестве таблицы БЕЗ ROWID, возможно, у вас есть составное УНИКАЛЬНОЕ ограничение.
Дополнительный комментарий: -
Как реализовать запрос, содержащий два или более тега одновременно
время
Это немного сложнее, если вы хотите определенные теги, но все же выполнимо. Вот пример использования CTE (Common Table Expression) вместе с предложением HAVING (предложение where применяется после генерации вывода, поэтому может применяться к агрегатам): -
WITH cte1(otm_oref,otm_tref,tt_id,tt_name, ot_id, ot_name) AS
(
SELECT * FROM object_tag_mapping
JOIN tag_table ON tag_reference = tag_table.id
JOIN object_table ON object_reference = object_table.id
WHERE tag_name = 'Pineapple' OR tag_name = 'Apple'
)
SELECT ot_name, group_concat(tt_name), count() AS cnt FROM CTE1
GROUP BY otm_oref
HAVING cnt = 2
;
В результате: -