使用三个SELECT优化SQL查询

时间:2012-11-21 18:13:40

标签: sql

我有以下表格:

news
idNews | title
1      | Title 1
2      | Title 2
3      | Title 3
4      | Title 4

tags
idTag | name
1     | Name_tag1
2     | Name_tag2
3     | Name_tag3
4     | Name_tag4

MappingTable:

tag_news
idTag | idNews
1     | 1
2     | 1
1     | 2
2     | 2
2     | 3
3     | 3
4     | 3
4     | 4

我想通过赠送一个idNews来获取几乎有一个共同标签的相关新闻的标题。我可以用三个SELECT来做到这一点:

SELECT title FROM news WHERE idNews IN 
 (SELECT DISTINCT idNews FROM tag_news 
  WHERE idTag IN 
  (SELECT idTag FROM tag_news WHERE idNews='$idNews'))

其中$ idNews标识我通过参数提供的ID。

这很有效,但我想如果还有其他方法可以改进查询。

提前致谢, 伊克尔

2 个答案:

答案 0 :(得分:6)

在SQL中编程时,您确实需要了解联接。连接是SQL的基础,因为while循环是大多数其他编程语言的基础。

SELECT DISTINCT n.title FROM news n
INNER JOIN tag_news t1 ON t1.idNews = n.idNews
INNER JOIN tag_news t2 ON t1.idTag = t2.idTag
WHERE t2.idNews = $idNews;

A Visual Explanation of SQL Joins

开始

来自@Beth的评论:

我并不是要与你发生冲突,但我很确定我的查询是正确的,并且它不需要三个连接。以下是它的工作原理:

  • t2tag_newst2.idNews=$idNews的行集。例如,如果$ idNews = 1,则会生成以下行:

    idTag | idNews
    1     | 1
    2     | 1
    
  • 从那里,我们希望tag_news中的所有其他行匹配任何相同的标记。所以t1.idTag=t2.idTag。这个产生给我们t1.idTag IN (1,2)

    的行
    idTag | idNews
    1     | 1
    2     | 1
    1     | 2
    2     | 2
    2     | 3
    
  • 从那里,返回news中与t1.idNews的任何值匹配的所有行。换句话说,news.idNews IN (1,2,3)

    idNews | title
    1      | Title 1
    2      | Title 2
    3      | Title 3
    

答案 1 :(得分:2)

尝试:

SELECT distinct title 
FROM  
tag_news t1  inner join 
tag_news t2 on
t1.idnews = t2.idnews inner join
tag_news t3 on
t2.idtag = t3.idtag inner join
news n on
n.idnews = t3.idnews
WHERE t1.idNews='$idNews'
抱歉,第一次和第二次错过了它:

CREATE TABLE [dbo].news(
    idnews [int] NOT NULL,
    title [varchar](50) NULL
) ON [PRIMARY]

insert into news(idnews, title) values(1,'title 1')
insert into news(idnews, title) values(2,'title 2')
insert into news(idnews, title) values(3,'title 3')
insert into news(idnews, title) values(4,'title 4')

CREATE TABLE [dbo].tag_news(
    idtag [int] NOT NULL,
    idnews [int] NOT NULL,
) ON [PRIMARY]

insert into tag_news(idtag, idnews) values(1,1)
insert into tag_news(idtag, idnews) values(2,1)
insert into tag_news(idtag, idnews) values(1,2)
insert into tag_news(idtag, idnews) values(2,2)
insert into tag_news(idtag, idnews) values(2,3)
insert into tag_news(idtag, idnews) values(3,3)
insert into tag_news(idtag, idnews) values(4,3)
insert into tag_news(idtag, idnews) values(4,4)

select * from news; 
select * from tag_news;

SELECT title FROM news WHERE idNews IN 
 (SELECT DISTINCT idNews FROM tag_news 
  WHERE idTag IN 
  (SELECT idTag FROM tag_news WHERE idNews=1));

SELECT distinct title 
FROM  
tag_news t1  inner join 
tag_news t2 on
t1.idnews = t2.idnews inner join
tag_news t3 on
t2.idtag = t3.idtag inner join
news n on
n.idnews = t3.idnews
WHERE t1.idNews=1;