当前位置: 首页 > 知识库问答 >
问题:

缩小多对多关系中可能的组合

时宾实
2023-03-14

我有以下3个数据库表:

足球:

  • id
  • 名称

标签:

  • id
  • 名称

Foobar_标签:

  • id
  • foobar_id
  • tag\u id

有许多Foobar,它们随机标记有一个或多个标记。

我收到标签列表-例如('tag1','tag2','tag3')

现在我想得到一个与foobar相关联的标签列表,其中foobar也与接收到的标签列表相关联。

为了更多地可视化这一点:

  • foobar_1有标签“tag1”、“tag2”
  • 结果:'tag2'
  • 结果:'tag2'
  • 结果:无

我使用的是Django,我目前的方法是这样的(foobar to tags是一个简单的m2m字段):

if tag_list:
    available_tags = Tag.objects
    for tag in tag_list:
        available_tags = available_tags.filter(foobar__tags__tag=tag).exclude(tag=tag)
    available_tags = available_tags.distinct()          
else:
    available_tags = Tag.objects.all()

available_tags = available_tags.annotate(num_foobars=Count('foobar', distinct=True)) \
                                                  .order_by('-num_foobars') \
                                                  .exclude(num_foobars=0)

我得到了我想要的结果,但我不确定我在这里使用了正确的方法。当只过滤2个标签时,生成的SQL已经包含8个INNER JOINS,并且每个添加的标签都增长得非常快,因此速度非常慢。

这是查找时生成的SQL('tag1','tag2')

SELECT DISTINCT 
    "tag"."id", 
    "tag"."name", 
    COUNT(DISTINCT "foobar_tags"."foobar_id") AS "num_foobars" 
FROM "tag" 
INNER JOIN "foobar_tags" ON ( "tag"."id" = "foobar_tags"."tag_id" ) 
INNER JOIN "foobar" ON ( "foobar_tags"."foobar_id" = "foobar"."id" ) 
INNER JOIN "foobar_tags" T4 ON ( "foobar"."id" = T4."foobar_id" ) 
INNER JOIN "tag" T5 ON ( T4."tag_id" = T5."id" ) 
INNER JOIN "foobar_tags" T6 ON ( "tag"."id" = T6."tag_id" ) 
INNER JOIN "foobar" T7 ON ( T6."foobar_id" = T7."id" ) 
INNER JOIN "foobar_tags" T8 ON ( T7."id" = T8."foobar_id" ) 
INNER JOIN "tag" T9 ON ( T8."tag_id" = T9."id" ) 
WHERE (T5."name" = 'tag1' 
    AND NOT ("tag"."name" = 'tag1') 
    AND T9."name" = 'tag2' 
    AND NOT ("tag"."name" = 'tag2')) 
GROUP BY "tag"."id", "tag"."name" 
HAVING NOT (COUNT(DISTINCT "foobar_tags"."foobar_id") = 0) 
ORDER BY "num_foobars" DESC
  • 查询是否可以优化(使用Django ORM或原始SQL)

共有1个答案

葛霄
2023-03-14

每个附加标签都不需要连接。假设查询包含tag1tag2,以下是它的sql:

select distinct tags.id, tags.name from tags inner join foobar_tags 
   on tags.id = foobar_tags.tagId 
   where fooId in 
      (select fooId from tags t inner join foobar_tags ft on t.id = ft.tagId 
          where 
             (select count(distinct name) from foobar_tags inner join tags 
               on tags.id = foobar_tags.tagId
               where fooId = ft.fooId and tags.name in('tag2','tag1')--tags query
             ) = 2 --number of tags in the query
    )
    AND
    name not in ('tag2','tag1')--tags query

我们通过计算属于我们的查询标记的相关标记,找到所有具有所有标记的foo。此计数应等于查询标记的数量。然后我们返回匹配的foo的标签,但不包括属于查询标签的标签。

您可以为任意数量的标记生成此查询,并且连接的数量将保持不变。

这是一把小提琴。

 类似资料:
  • 我还想知道如何定义每个模型上的关系--你是否需要或者是否可以只在用户上定义关系?

  • 问题内容: 我有一个Firebase数据库。我有公司和承包商。一个承包商可以为多个公司工作,而一个公司可以有多个承包商。这是直接的多对多关系。我希望能够回答有关公司和承包商的问题: 给定一家公司,他们是当前的承包商。 给承包商一个他们要工作的公司。 在Firebase中构造数据的替代方法有哪些? 问题答案: 自我回答确实是对此进行建模的一种方法。它可能是在关系数据库中建模的最直接等效方法: 承办商

  • 问题内容: 我知道在Elasticsearch中,我们可以在文档之间建立子/父关系。 然后,在建立索引时,我可以传递父代ID,以便将子文档和父文档链接起来: 无论如何,在Elasticsearch中建立多对多关系的模型吗? 数据驻留在具有以下架构的MySQL数据库中: 当前这是我的映射(请原谅数组表示法,我在PHP中使用Elastica与我的Elasticsearch服务器通信): 这种方法的问题

  • 我有一个Firebase数据库。我有公司和承包商。一个承包商可以为多个公司工作,一个公司可以有多个承包商。这是一种简单的多对多关系。我希望能够回答有关公司和承包商的问题: 给定一家公司,谁是当前的承包商 给定一个承包商,他们为哪些公司工作 在firebase中构建数据的替代方案是什么?

  • 问题内容: 伙计们,我正在努力为我的公司制作一个简单的票证生成系统,以吸引人。目前,我的MSSQL数据库中有一个名为的表,另一个名为的表。 我的应用程序是C#Windows窗体,因此在新的票证生成窗体上,我有许多文本框和一个用于分配工程师的comboBox,由填充。生成票证后,以这种形式输入的所有信息都将与from一起存储。 效果很好,但是后来我的客户要求我添加选项,以便可以在一张票上分配3名工程