Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.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
使用SQLite中的筛选器和分页查询多对多关系_Sqlite_Join_Nested - Fatal编程技术网

使用SQLite中的筛选器和分页查询多对多关系

使用SQLite中的筛选器和分页查询多对多关系,sqlite,join,nested,Sqlite,Join,Nested,我试图对博客文章列表进行分页,并根据它们在SQLite数据库中可能具有的标记列表对其进行过滤 帖子和标签有一个n对n的关系,所以我创建了一个PostTag关系表 CREATE TABLE "Post" ( "Id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, "Title" TEXT ); CREATE TABLE "Tag" ( "Id" INTEGER NOT NULL PRIMARY KEY

我试图对博客文章列表进行分页,并根据它们在SQLite数据库中可能具有的标记列表对其进行过滤

帖子和标签有一个n对n的关系,所以我创建了一个PostTag关系表

CREATE TABLE "Post" (
    "Id"    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
    "Title" TEXT
);


CREATE TABLE "Tag" (
    "Id"    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
    "Label" TEXT
);


CREATE TABLE "PostTag" (
    "Id"    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
    "PostId"    INTEGER,
    "TagId" INTEGER,
    FOREIGN KEY("PostId") REFERENCES "Post"("Id"),
    FOREIGN KEY("TagId") REFERENCES "Tag"("Id")
);
鉴于以下数据

INSERT INTO Post (Title) VALUES ('Post title 1'), ('Post title 2'), ('Post title 3');
INSERT INTO Tag (Label) VALUES ('news'), ('funny'), ('review');
INSERT INTO PostTag (PostId, TagId) VALUES (1, 1), (1, 2), (2, 3), (3, 2), (3, 3);
我正在尝试选择10篇既有“新闻”标签又有“有趣”标签的帖子,因此我只希望返回“帖子标题1”以进行澄清:我需要在这里返回两次帖子1,一次带“新闻”标签,一次带“有趣”标签

我使用DENSE_RANK在结果中实际有10个不同的帖子,即使连接可能返回10行以上

我遇到的问题是如何管理标签值上的“AND”操作符,即不返回只有一个标签的帖子。所以在这里,我不想让Post3被返回,因为它只有“搞笑”标签,而没有“新闻”标签

下面是我迄今为止更新的最好的查询,它将返回包含“新闻”或“有趣”的帖子,这不是我想要的:

SELECT * FROM (
    SELECT p.*, t.*, DENSE_RANK() OVER(order by p.id desc) rnk
    FROM Post p
    JOIN PostTag pt ON p.Id = pt.PostId
    JOIN Tag t ON pt.TagId = t.Id AND t.Label IN ('news', 'funny')
    ORDER BY p.id desc
) ranked
WHERE rnk <= 10
如果稍后有人向post 1添加标记,如下所示:

INSERT INTO Tag (Label) VALUES ('tech'); -- id is 4
INSERT INTO PostTag (PostId, TagId) VALUES (1, 4);
查询的结果应该是

Id          Title           Id:2            Label           rnk
1           'Post Title 1'  1               'news'          1
1           'Post Title 1'  2               'funny'         1
1           'Post Title 1'  4               'tech'          1
因此,我可以显示匹配的文章及其所有标记,即使该标记不在查询中

我终于有了一些工作,但它是可怕的嵌套,我真诚地想知道为什么这个问题是如此复杂。难道没有一种直接依靠等级的方法吗

select * from ( 
    select  *, dense_rank() over(order by p.id desc) rnk 
    from Post p 
    join PostTag pt on p.Id = pt.PostId 
    join Tag t on pt.TagId = t.Id 
    and postId in (
        select postId from (
            select dense_rank() over(order by pt2.PostId) rnk2,
            from PostTag pt2 
            join Tag t2 on pt2.TagId = t2.Id 
            where t2.Label in ('news', 'funny')
        )
        group by rnk2
        having count(rnk2) == 2 -- 2 being the number of tags requested
    ) order by p.id desc 
) 
ranked where rnk <= 10

您可以通过一个简单的分组来完成,如下所示:

select p.id, p.title
from posttag pt
inner join post p on p.id = pt.postid
inner join tag t on t.id = pt.tagid
where t.label in ('news', 'funny')
group by p.id, p.title
having count(distinct t.id) = 2
order by p.id limit 10

请参阅。

以给您一个想法

select * from (
    select p.*, t.*, dense_rank() over(order by p.id desc) rnk
    from Post p
    join PostTag on p.Id = PostId
    join Tag t on TagId = t.Id
    and postid in (select postid
                     from posttag join tag t on tagid = t.id
                     where label in ('news', 'funny')
                     group by postid having count(distinct tagid) > 1)
    order by p.id desc
) ranked
where rnk <= 10;

这几乎没问题,但我需要检索与帖子相关的所有标记,然后进行重复数据消除。顺便说一下,如果第1篇文章附加了另一个标签,比如“2019”,那么它也应该出现在结果中@tonypdmtr的解决方案就是这样的。我正在尝试选择10篇文章,它们都有标签“news”和“funcy”。这是你问的,这就是代码的作用。好吧,我的错,我没有明确提到我需要在结果中返回每个文章的单独标签。这很有效,谢谢!正如我刚才对forpas所说的,我还需要返回与post 1相关联的潜在其他标记,这与您的查询一起工作。老实说,我真的很难理解,哈哈。用countdistinct postid替换count*,以防PostTag条目允许重复元组。我原本以为它们是不允许的,但表结构允许它们。很抱歉,我不得不取消接受您的答案,因为IN子查询返回的POSTID永远不会超过请求的不同标记数。这恰好适用于我非常简单的数据集,但只要有2篇文章匹配了这两个标记,就会只返回其中一个。是否应该改为>1=={查询的标记数}?或者大于1减去if标记数。不管怎样。也许我的方法不好,也许我不应该尝试在单独的帖子行上返回标签。。。
select * from (
    select p.*, t.*, dense_rank() over(order by p.id desc) rnk
    from Post p
    join PostTag on p.Id = PostId
    join Tag t on TagId = t.Id
    and postid in (select postid
                     from posttag join tag t on tagid = t.id
                     where label in ('news', 'funny')
                     group by postid having count(distinct tagid) > 1)
    order by p.id desc
) ranked
where rnk <= 10;