除了这个问题SQL query that gives distinct results that match multiple columns 我有一个非常简洁的解决方案,我想知道下一步将如何看待:
DOCUMENT_ID | TAG
----------------------------
1 | tag1
1 | tag2
1 | tag3
2 | tag2
3 | tag1
3 | tag2
4 | tag1
5 | tag3
因此,要获取包含标记1和2的所有document_ids,我们将执行如下查询:
SELECT document_id
FROM table
WHERE tag = 'tag1' OR tag = 'tag2'
GROUP BY document_id
HAVING COUNT(DISTINCT tag) = 2
现在,有趣的是,我们将如何获得具有标签1和2的所有不同document_ids,以及具有标签3的ID。 我们可以想象制作相同的查询并在它们之间执行联合:
SELECT document_id
FROM table
WHERE tag = "tag1" OR tag = "tag2"
GROUP BY document_id
HAVING COUNT(DISTINCT tag) = 2
UNION
SELECT document_id
FROM table
WHERE tag = "tag3"
GROUP BY document_id
但我想知道是否添加了这个条件,我们可以想到另一个初始查询。我想象有许多“工会”,有不同的标签和标签计数。 在创建这样的工会链方面,在性能方面不是很糟糕吗?
答案 0 :(得分:2)
这仍然使用各种联合,但可能更容易阅读和控制。我对这个查询在大型数据集上的速度非常感兴趣,所以请告诉我它有多快。当我输入你的小数据集时,花了0.0001秒。
SELECT DISTINCT (dt1.document_id)
FROM
document_tag dt1,
(SELECT document_id
FROM document_tag
WHERE tag = 'tag1'
) AS t1s,
(SELECT document_id
FROM document_tag
WHERE tag = 'tag2'
) AS t2s,
(SELECT document_id
FROM document_tag
WHERE tag = 'tag3'
) AS t3s
WHERE
(dt1.document_id = t1s.document_id
AND dt1.document_id = t2s.document_id
)
OR dt1.document_id = t3s.document_id
这样可以轻松添加新参数,因为您已经为每个标记指定了结果集。
例如添加:
OR dt1.document_id = t2s.document_id
到最后还会拿起document_id 2
答案 1 :(得分:0)
可以在单个内执行此操作,但是您需要将WHERE子句提升为having子句才能使用析取。
答案 2 :(得分:0)
你是对的,当你在其他UNION子句中添加想要查找的新标签时,这会变得越来越慢。每个UNION子句都是需要计划和执行的附加查询。另外,当你完成后,你将无法进行排序。
您正在寻找基本的数据仓库技术。首先,让我用一个额外的表重新创建你的模式。
create table a (document_id int, tag varchar(10));
insert into a values (1, 'tag1'), (1, 'tag2'), (1, 'tag3'), (2, 'tag2'),
(3, 'tag1'), (3, 'tag2'), (4, 'tag1'), (5, 'tag3');
create table b (tag_group_id int, tag varchar(10));
insert into b values (1, 'tag1'), (1, 'tag2'), (2, 'tag3');
表b包含“标签组”。第1组包括tag1和tag2,而第2组包含tag3。
现在您可以修改表b来表示您感兴趣的查询。当您准备好查询时,您可以创建临时表来存储聚合数据:
create temporary table c
(tag_group_id int, count_tags_in_group int, tags_in_group varchar(255));
insert into c
select
tag_group_id,
count(tag),
group_concat(tag)
from b
group by tag_group_id;
create temporary table d (document_id int, tag_group_id int, document_tag_count int);
insert into d
select
a.document_id,
b.tag_group_id,
count(a.tag) as document_tag_count
from a
inner join b on a.tag = b.tag
group by a.document_id, b.tag_group_id;
现在c包含标签组的标签数量,d包含每个文档对每个标签组的标签数量。如果c中的行与d中的行匹配,则表示该文档包含该标记组中的所有标记。
select
d.document_id as "Document ID",
c.tags_in_group as "Matched Tag Group"
from d
inner join c on d.tag_group_id = c.tag_group_id
and d.document_tag_count = c.count_tags_in_group
这种方法的一个很酷的事情是你可以运行报告,例如“每个标签组中有多少文件有50%或更多的标签?”
select
d.document_id as "Document ID",
c.tags_in_group as "Matched Tag Group"
from d
inner join c on d.tag_group_id = c.tag_group_id
and d.document_tag_count >= 0.5 * c.count_tags_in_group