Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何编写更好的跨行匹配多个值的多重联接?_Sql - Fatal编程技术网

Sql 如何编写更好的跨行匹配多个值的多重联接?

Sql 如何编写更好的跨行匹配多个值的多重联接?,sql,Sql,我正在尝试编写一个SQL语句,允许我根据关键字从表中选择一系列文章。到目前为止,我得到的是一个令牌表、一个项目表和一个令牌和项目的多对多表: tokens rowid token token_article token_rowid article_rowid articles rowid 我正在做的是获取一个搜索查询,按空格将其拆分,然后选择所有包含这些关键字的文章。到目前为止,我已经想到了这个: select * from (select * from to

我正在尝试编写一个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的文章和所有定义的文章进行选择,然后选择它们

现在我在想一个更好的办法。我在脑海中想象的是,选择所有与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.