我有多对多的网站和代码,通过联接表SitesTags连接:
Site
has_and_belogs_to_many :tags
id name
1 siteA
2 siteB
Tag
# has_and_belogs_to_many :sites
id name
1 tagA
2 tagB
3 tagC
SitesTags
site_id tag_id
1 1
1 2
2 2
2 3
我想获得两个网站共有的COUNT个标签。 在此示例中,将有一个常用标记siteA和siteB(tagB)。
理想情况下,我想要数据库级别的解决方案,但我正在使用MySQL。
我试过(Site.find(1).tags & Site.find(2).tags).count
但是我可以看到这是在进行多次查询,并且它不是使用COUNT(*)而是获取所有数据:
Site Load (0.3ms) SELECT `sites`.* FROM `sites` WHERE `sites`.`id` = 1 LIMIT 1
Site Load (0.3ms) SELECT `sites`.* FROM `sites` WHERE `sites`.`id` = 2 LIMIT 1
Tag Load (0.3ms) SELECT `tags`.* FROM `tags` INNER JOIN `sites_tags` ON `tags`.`id` = `sites_tags`.`tag_id` WHERE `sites_tags`.`site_id` = 1
Tag Load (0.4ms) SELECT `tags`.* FROM `tags` INNER JOIN `sites_tags` ON `tags`.`id` = `sites_tags`.`tag_id` WHERE `sites_tags`.`site_id` = 2
我尝试过的另一件事是
Site.find(1).tags.where("`sites_tags`.`site_id` = 2")
正在生成
SELECT `tags`.* FROM `tags` INNER JOIN `sites_tags` ON `tags`.`id` = `sites_tags`.`tag_id` WHERE `sites_tags`.`site_id` = 1 AND (`sites_tags`.`site_id` = 2)
这不起作用,我认为它试图找到site_id为1和2的单个记录
答案 0 :(得分:0)
要计算,请尝试:
Site.find(1).tags.count
要获得site1
和site2
中常见的标记计数:
s1 = Site.find(1).tags.map(&:name)
s2 = Site.find(2).tags.map(&:name)
common_tags s1 & s2
答案 1 :(得分:0)
对于数据库级别的解决方案,您可以使用原始sql来获取常用标记的数量:
sql = <<~SQL
SELECT COUNT(DISTINCT(a.tag_id))
FROM sites_tags a JOIN sites_tags b ON a.tag_id = b.tag_id
WHERE a.site_id != b.site_id
AND a.site_id IN (1, 2);
SQL
count = ActiveRecord::Base.connection.select_rows(sql).flatten
#=> [1]
或者,如果您想要一个名为所有常用标签的数组(并在以后计算),您可以使用此查询:
sql = <<~SQL
SELECT DISTINCT(c.name)
FROM sites_tags a
JOIN sites_tags b ON a.tag_id = b.tag_id
JOIN tags c ON a.tag_id = c.id
WHERE a.site_id != b.site_id
AND a.site_id IN (1, 2);
SQL
tags = ActiveRecord::Base.connection.select_rows(sql).flatten
#=> ["tagB"]
两者都适用于MySQL。
答案 2 :(得分:0)
使用合并
Site.find(1).tags.merge(Site.find(2).tags).count
它将在3个有效查询中完成