基于标签的 SQL 查询
Posted
技术标签:
【中文标题】基于标签的 SQL 查询【英文标题】:Tag based SQL query 【发布时间】:2013-02-04 09:09:49 【问题描述】:我已经有一段时间没有做任何 SQL 了,我不确定这个问题是否有一个简单的解决方案。我也是一个菜鸟。
我正在尝试建立一个图片库,允许用户使用标签来搜索图片,然后单击其他标签来优化搜索并减少结果数量,但我对查询有很大的问题参与。
这是我当前数据库结构的简化版本:
(2个表和一个额外的多对多链接表)
CREATE TABLE images(
image_id INT(12) AUTO_INCREMENT,
image_name VARCHAR(128),
PRIMARY KEY(image_id)
)ENGINE= INNODB;
CREATE TABLE tags(
tag_name VARCHAR(64) NOT NULL,
PRIMARY KEY(tag_name)
)ENGINE= INNODB;
CREATE TABLE images_tags_link(
image_id_fk INT(12),
tag_name_fk VARCHAR(64) NOT NULL,
PRIMARY KEY(image_id_fk,tag_name_fk),
FOREIGN KEY(image_id_fk) REFERENCES images(image_id),
FOREIGN KEY(tag_name_fk) REFERENCES tags(tag_name)
)ENGINE= INNODB;
样本数据:
===images===
___________________________
| image_id | image_name |
|----------|----------------|
| 1 | image_001.jpg |
| 2 | image_002.jpg |
| 3 | image_003.png |
| 4 | image_004.jpg |
| 5 | image_005.gif |
---------------------------
===tags===
_______________
| tag_name |
|---------------|
| Landscape |
| Portrait |
| Illustration |
| Photo |
| Red |
| Blue |
| Character |
| Structure |
---------------
===images_tags_link===
________________________________
| image_id_fk | tag_name_ fk |
|-------------|------------------|
| 1 | Landscape |
| 1 | Illustration |
| 1 | Blue |
| 2 | Blue |
| 2 | structure |
| 2 | Landscape |
| 3 | Illustration |
| 4 | Red |
| 4 | Portrait |
| 4 | Character |
| 5 | Blue |
| 5 | Photo |
--------------------------------
我的问题在于以下查询:
我正在寻找一个查询,它可以从 IMAGES 表中选择所有包含所有用户列出的标签的“image_names”,例如,用户可以搜索“Blue”和“Landscape”标签,它应该只输出image_names 'image_001.jpg' AND 'image_002.jpg'。
===输入===
用户选择的标签:( 'Blue' , 'Landscape' )
===输出===
具有所有列出标签的图像名称:('image_001.jpg','image_002.jpg')
提前致谢。
【问题讨论】:
【参考方案1】:这就是他们所谓的Relation Division,这是一种方法:
SELECT i.*
FROM Images i
INNER JOIN
(
SELECT image_id_fk
FROM images_tags_link
WHERE tag_name_fk IN ('Blue' , 'Landscape')
GROUP BY image_id_fk
HAVING COUNT(DISTINCT tag_name_fk) = 2
) t ON i.image_id = t.image_id_fk;
SQL Fiddle Demo
这会给你:
| IMAGE_ID | IMAGE_NAME |
----------------------------
| 1 | image_001.jpg |
| 2 | image_002.jpg |
这个查询背后的想法是:
GROUP BY image_id_fk
HAVING COUNT(DISTINCT tag_name_fk) = 2
在子查询中,这将确保任何图像都有两个标签,如果它只有一个,则COUNT
将为0,因此将被淘汰。
【讨论】:
这个也有效,但我不知道为什么。感谢您提供我需要阅读的链接。【参考方案2】:两种简单的方法。
以下任意一种,取决于所需的列、可能的标签数量等。
SELECT *
FROM images
INNER JOIN images_tags_link a ON images.image_id = a.image_id_fk AND a.tag_name_fk = 'Blue'
INNER JOIN images_tags_link b ON images.image_id = b.image_id_fk AND b.tag_name_fk = 'Landscape'
SELECT images.image_id, images.image_name, COUNT(*) AS tag_count
FROM images
INNER JOIN images_tags_link a ON images.image_id = a.image_id_fk
WHERE a.tag_name_fk IN ('Blue', 'Landscape')
GROUP BY images.image_id, images.image_name
HAVING tag_count = 2
【讨论】:
感谢您的帮助,我设法让这两个查询正常工作。 这里应该说第二个query或者gamal的回答比较快。【参考方案3】:这是另一个使用 EXISTS 的示例:
SELECT *
FROM Images I
WHERE EXISTS (
SELECT image_id_fk
FROM Images_Tags_Link I2
WHERE I2.image_id_fk = I.Image_Id
AND tag_name_fk IN ('Blue' , 'Landscape')
GROUP BY I2.image_id_fk
HAVING COUNT(DISTINCT I2.tag_name_fk) > 1)
还有一个使用 IN:
SELECT *
FROM Images I
WHERE Image_Id IN (
SELECT image_id_fk
FROM Images_Tags_Link I2
WHERE I2.image_id_fk = I.Image_Id
AND tag_name_fk IN ('Blue' , 'Landscape')
GROUP BY I2.image_id_fk
HAVING COUNT(DISTINCT I2.tag_name_fk) > 1)
祝你好运。
【讨论】:
【参考方案4】:试试这个更简单的方法
选择 图像名称 来自 images_tags_link tag_name_fk in ('Blue','Landscape')
【讨论】:
我尝试了与之前类似的查询。对我来说,问题是它不断向我输出具有一个或两个标签的图像,而不仅仅是同时具有两个标签的图像。以上是关于基于标签的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章