Sql 如何编写更好的跨行匹配多个值的多重联接?
我正在尝试编写一个SQL语句,允许我根据关键字从表中选择一系列文章。到目前为止,我得到的是一个令牌表、一个项目表和一个令牌和项目的多对多表:Sql 如何编写更好的跨行匹配多个值的多重联接?,sql,Sql,我正在尝试编写一个SQL语句,允许我根据关键字从表中选择一系列文章。到目前为止,我得到的是一个令牌表、一个项目表和一个令牌和项目的多对多表: tokens rowid token token_article token_rowid article_rowid articles rowid 我正在做的是获取一个搜索查询,按空格将其拆分,然后选择所有包含这些关键字的文章。到目前为止,我已经想到了这个: select * from (select * from to
tokens
rowid
token
token_article
token_rowid
article_rowid
articles
rowid
我正在做的是获取一个搜索查询,按空格将其拆分,然后选择所有包含这些关键字的文章。到目前为止,我已经想到了这个:
select * from
(select * from tokens
inner join token_article on
tokens.rowid = token_article.token_rowid and
token = 'ABC'
) as t1,
(select * from tokens
inner join token_article on
tokens.rowid = token_article.token_rowid and
token = 'DEF'
) as t2
where t1.article_rowid = t2.article_rowid and t2.article_rowid = articles.rowid
这是可行的,但当然它会对所有符合ABC的文章和所有定义的文章进行选择,然后选择它们
现在我在想一个更好的办法。我在脑海中想象的是,选择所有与ABC匹配的文章,并从中选择任何与DEF匹配的文章。这是我想象中的样子,但不起作用(接收错误消息“no-This columns:tokens.rowid”)
这里有一种方法。该脚本已在SQL Server 2012数据库中测试 脚本: 输出:
这里有一种方法。该脚本已在SQL Server 2012数据库中测试 脚本: 输出:
因为有不止一种方法可以做到这一点…这个方法使用GROUPBY和HAVING子句。查询将查找具有ABC或DEF标记的所有项目,然后根据项目ID进行分组,其中项目的标记计数等于所查询的标记数 注意,我在这里使用了MSSQL语法,但是这个概念应该适用于大多数SQL实现 Edit:我应该指出,当您向查询添加更多标记时,这有一个相当干净的语法。如果添加更多令牌,则只需修改条件中的
t.token\u,并相应地调整HAVING COUNT(*)=x
子句
DECLARE @tokens TABLE
(
rowid INT NOT NULL,
token VARCHAR(255) NOT NULL
)
DECLARE @articles TABLE
(
rowid INT NOT NULL,
title VARCHAR(255) NOT NULL
)
DECLARE @token_article TABLE
(
token_rowid INT NOT NULL,
article_rowid INT NOT NULL
)
INSERT INTO @tokens VALUES (1, 'ABC'), (2, 'DEF')
INSERT INTO @articles VALUES (1, 'This is article 1.'), (2, 'This is article 2.'), (3, 'This is article 3.'), (4, 'This is article 4.'), (5, 'This is article 5.'), (6, 'This is article 6.')
INSERT INTO @token_article VALUES (1, 1), (2, 1), (1, 2), (2, 3), (1, 4), (2, 4), (1, 5), (1, 6)
-- Get the article IDs that have all of the tokens
-- Use this if you just want the IDs
SELECT a.rowid FROM @articles a
INNER JOIN @token_article ta ON a.rowid = ta.article_rowid
INNER JOIN @tokens t ON ta.token_rowid = t.rowid
WHERE t.token IN ('ABC', 'DEF')
GROUP BY a.rowid
HAVING COUNT(*) = 2 -- This should match the number of tokens
rowid
-----------
1
4
-- Get the articles themselves
-- Use this if you want the articles
SELECT * FROM @articles WHERE rowid IN (
SELECT a.rowid FROM @articles a
INNER JOIN @token_article ta ON a.rowid = ta.article_rowid
INNER JOIN @tokens t ON ta.token_rowid = t.rowid
WHERE t.token IN ('ABC', 'DEF')
GROUP BY a.rowid
HAVING COUNT(*) = 2 -- This should match the number of tokens
)
rowid title
----------- ------------------
1 This is article 1.
4 This is article 4.
因为有不止一种方法可以做到这一点…这个方法使用GROUPBY和HAVING子句。查询将查找具有ABC或DEF标记的所有项目,然后根据项目ID进行分组,其中项目的标记计数等于所查询的标记数
注意,我在这里使用了MSSQL语法,但是这个概念应该适用于大多数SQL实现
Edit:我应该指出,当您向查询添加更多标记时,这有一个相当干净的语法。如果添加更多令牌,则只需修改
条件中的t.token\u,并相应地调整HAVING COUNT(*)=x
子句
DECLARE @tokens TABLE
(
rowid INT NOT NULL,
token VARCHAR(255) NOT NULL
)
DECLARE @articles TABLE
(
rowid INT NOT NULL,
title VARCHAR(255) NOT NULL
)
DECLARE @token_article TABLE
(
token_rowid INT NOT NULL,
article_rowid INT NOT NULL
)
INSERT INTO @tokens VALUES (1, 'ABC'), (2, 'DEF')
INSERT INTO @articles VALUES (1, 'This is article 1.'), (2, 'This is article 2.'), (3, 'This is article 3.'), (4, 'This is article 4.'), (5, 'This is article 5.'), (6, 'This is article 6.')
INSERT INTO @token_article VALUES (1, 1), (2, 1), (1, 2), (2, 3), (1, 4), (2, 4), (1, 5), (1, 6)
-- Get the article IDs that have all of the tokens
-- Use this if you just want the IDs
SELECT a.rowid FROM @articles a
INNER JOIN @token_article ta ON a.rowid = ta.article_rowid
INNER JOIN @tokens t ON ta.token_rowid = t.rowid
WHERE t.token IN ('ABC', 'DEF')
GROUP BY a.rowid
HAVING COUNT(*) = 2 -- This should match the number of tokens
rowid
-----------
1
4
-- Get the articles themselves
-- Use this if you want the articles
SELECT * FROM @articles WHERE rowid IN (
SELECT a.rowid FROM @articles a
INNER JOIN @token_article ta ON a.rowid = ta.article_rowid
INNER JOIN @tokens t ON ta.token_rowid = t.rowid
WHERE t.token IN ('ABC', 'DEF')
GROUP BY a.rowid
HAVING COUNT(*) = 2 -- This should match the number of tokens
)
rowid title
----------- ------------------
1 This is article 1.
4 This is article 4.
没错!谢谢我真的很感谢您添加了如何添加更多令牌,因为我的示例只是一个简单的例子。就是这样!谢谢我真的很感谢你添加了如何添加更多令牌,因为我的示例只是一个简单的例子。谢谢你的回复!你的回答和迈克尔·迪恩的回答都很有帮助。谢谢谢谢你的回复!你的回答和迈克尔·迪恩的回答都很有帮助。谢谢
rowid token token_rowid article_rowid token_rowid article_rowid rowid token
----- ----- ----------- ------------- ----------- ------------- ----- -----
1 ABC 1 2 2 2 2 DEF
1 ABC 1 3 2 3 2 DEF
DECLARE @tokens TABLE
(
rowid INT NOT NULL,
token VARCHAR(255) NOT NULL
)
DECLARE @articles TABLE
(
rowid INT NOT NULL,
title VARCHAR(255) NOT NULL
)
DECLARE @token_article TABLE
(
token_rowid INT NOT NULL,
article_rowid INT NOT NULL
)
INSERT INTO @tokens VALUES (1, 'ABC'), (2, 'DEF')
INSERT INTO @articles VALUES (1, 'This is article 1.'), (2, 'This is article 2.'), (3, 'This is article 3.'), (4, 'This is article 4.'), (5, 'This is article 5.'), (6, 'This is article 6.')
INSERT INTO @token_article VALUES (1, 1), (2, 1), (1, 2), (2, 3), (1, 4), (2, 4), (1, 5), (1, 6)
-- Get the article IDs that have all of the tokens
-- Use this if you just want the IDs
SELECT a.rowid FROM @articles a
INNER JOIN @token_article ta ON a.rowid = ta.article_rowid
INNER JOIN @tokens t ON ta.token_rowid = t.rowid
WHERE t.token IN ('ABC', 'DEF')
GROUP BY a.rowid
HAVING COUNT(*) = 2 -- This should match the number of tokens
rowid
-----------
1
4
-- Get the articles themselves
-- Use this if you want the articles
SELECT * FROM @articles WHERE rowid IN (
SELECT a.rowid FROM @articles a
INNER JOIN @token_article ta ON a.rowid = ta.article_rowid
INNER JOIN @tokens t ON ta.token_rowid = t.rowid
WHERE t.token IN ('ABC', 'DEF')
GROUP BY a.rowid
HAVING COUNT(*) = 2 -- This should match the number of tokens
)
rowid title
----------- ------------------
1 This is article 1.
4 This is article 4.