首页 > 解决方案 > 多对多单查询优化

问题描述

我有 3 个具有多对多关系的表

 CREATE TABLE news(id int, content varchar(64));
CREATE TABLE tags(id int, name varchar(64));
CREATE TABLE news_tags(id int, tag_id int, news_id int);

INSERT INTO news VALUES
(1, "Hello, world!"),
(2, "Test news"),
(3, "test news 2"),
(4, "test news 3"),
(5, "test news 4");

INSERT INTO tags VALUES
(1, "general tag"),
(2, "sub tag 1"),
(3, "sub tag 2"),
(4, "normal tag");

INSERT INTO news_tags VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1);


INSERT INTO news_tags VALUES
(4, 1, 2),
(5, 2, 2),

(6, 1, 3),
(7, 4, 3),

(7, 2, 4),
(8, 3, 4),

(9, 1, 5);

我要选择 news_id 什么

  1. 在关系上只有一般(例如 id 1)标签并且没有任何其他子标签(在 exmpl id 3 上)

  2. 有一对通用标签+子标签(id 2)

我创建一个查询

SELECT news_id FROM news_tags WHERE tag_id = 1 OR tag_id = 2 
    GROUP BY news_id 
    HAVING COUNT(news_id) = 2
UNION
SELECT news_id FROM news_tags WHERE tag_id = 1 AND news_id not in (SELECT news_id FROM news_tags WHERE tag_id in (2,3));

但有2个问题

  1. 我认为它不是优化方式(有 2 选择与联合 + 子选择查询)

  2. 如果我要搜索更多一对子标签,我需要使用联合添加新选择

我怎样才能优化这个查询?

现场示例http://www.sqlfiddle.com/#!9/1067b7/1/0

标签: mysqlsqldatabase

解决方案


您的问题不清楚,因为未定义“子”标签和“一般”标签的概念。

但是如果你想同时处理多个条件,你仍然可以使用一个GROUP BYandHAVING子句。

例如,如果您想要news_id满足以下任一条件的 s:

  • tag_id= 1
  • 或者两者都tag_id= 2 和tag_id= 3

然后你可以使用:

SELECT nt.news_id
FROM news_tags nt
GROUP BY nt.news_id 
HAVING (COUNT(*) = 1 AND MIN(nt.tag_id) = 1) OR
       SUM( nt.tag_id IN (2, 3) ) = 2;

您可以轻松地将这个想法扩展到标签的描述(但您需要为此加入tags表格。


推荐阅读