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'
)
4

2 に答える 2

2

これを行うには複数の方法があるため...この方法では GROUP BY 句と HAVING 句を使用します。クエリは、ABC トークンまたは DEF トークンのいずれかを持つすべての記事を検索しますが、記事のトークン数がクエリ対象のトークン数と等しい記事 ID でグループ化します。

ここでは 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.
于 2012-04-28T13:46:30.217 に答える
1

これを行う1つの方法があります。スクリプトはSQLServer2012データベースでテストされました。

スクリプト

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
于 2012-04-28T13:32:49.867 に答える