2012-04-28 21 views
0

我正在尝试编写一个SQL语句,该语句将允许我根据关键字从表中选择一系列文章。我有这么远是一个符号表,文章表,和许多一对多表令牌&文章:如何编写一个更好的多行连接来匹配跨行的多个值?

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的所有文章和所有文章,DEF然后选择它们。

现在我试图找出更好的方法。我认为在我看来,这将起作用的是选择所有与ABC匹配的文章,并从那些与DEF匹配。这就是我想象它的样子,但不工作(收到错误消息“没有这样的列:tokens.rowid”)

select * from 
    (select * from 
     (select * from tokens 
       inner join token_article on 
        tokens.rowid = token_article.token_rowid and 
      token = 'ABC' 
     ) 
    inner join token_article on 
      tokens.rowid = token_article.token_rowid and 
    token = 'DEF' 
) 

回答

2

因为没有做到这一点不止一种方法......这个方法使用GROUP BY和HAVING子句。该查询正在查找具有ABC或DEF令牌的所有文章,但随后按文章标识进行分组,其中文章的标记数等于被查询的标记数。

请注意,我在这里使用了MSSQL语法,但是这个概念应该可以在大多数SQL实现中使用。

编辑︰我应该指出,这有一个相当干净的语法,因为你添加更多的标记的查询。如果添加更多的标记,则只需修改t.token_in条件并相应地调整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. 
+0

正是它!谢谢!我非常感谢你加入了如何添加更多的标记,因为我的例子只是一个简单的例子。 – jmricker 2012-04-28 17:00:21

1

下面是做到这一点的方法之一。该脚本在SQL Server 2012数据库中进行了测试。

脚本

CREATE TABLE dbo.tokens 
(
     rowid INT   NOT NULL IDENTITY 
    , token VARCHAR(10) NOT NULL 
); 

CREATE TABLE dbo.articles 
(
     rowid INT   NOT NULL IDENTITY 
    , name VARCHAR(10) NOT NULL 
); 

CREATE TABLE dbo.token_article 
(
     token_rowid  INT NOT NULL 
    , article_rowid INT NOT NULL 
); 

INSERT INTO dbo.tokens (token) VALUES 
    ('ABC'), 
    ('DEF'); 

INSERT INTO dbo.articles (name) VALUES 
    ('Article 1'), 
    ('Article 2'), 
    ('Article 3'); 

INSERT INTO dbo.token_article (token_rowid, article_rowid) VALUES 
    (1, 2), 
    (2, 3), 
    (1, 3), 
    (1, 1), 
    (2, 2); 

SELECT out1.rowid 
    , out1.token 
    , out1.token_rowid 
    , out1.article_rowid 
    , ta2.token_rowid 
    , ta2.article_rowid 
    , t2.rowid 
    , t2.token 
FROM 
(
    SELECT  t.rowid 
      , t.token 
      , ta1.token_rowid 
      , ta1.article_rowid 
    FROM  dbo.tokens   t 
    INNER JOIN dbo.token_article ta1 
    ON   ta1.token_rowid  = t.rowid 
    WHERE  t.token    = 'ABC' 
)   out1 
INNER JOIN dbo.token_article ta2 
ON   ta2.article_rowid = out1.article_rowid 
INNER JOIN dbo.tokens   t2 
ON   t2.rowid   = ta2.token_rowid 
AND   t2.token   = 'DEF'; 

输出

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 
+0

感谢您的回复!你的回应和Michael Dean的回应非常有帮助。谢谢! – jmricker 2012-04-28 17:05:20

相关问题