select 用标签列表标记的所有行

select all rows tagged with a list of tags

我想出了这个查询来查找所有标记有特定标签列表的人:

select * from people
where ARRAY[?]::character varying[] <@ ARRAY(
      select tags.name
      from tags
      inner join taggings on tags.id = taggings.tag_id
      where taggings.taggable_type = 'Person' and
            taggings.taggable_id = people.id)

不知怎的,我觉得我把事情搞得太复杂了。现在我们没有足够的数据来证明它的表现不佳,但真的没有更好的方法吗?

编辑: 最小 table 定义:

create table people (
    id integer
);

create table tags (
    id integer,
    name text
);

create table taggings (
    id integer,
    tag_id integer,
    taggalbe_type text,
    taggable_id integer
);

最少的数据:

insert into people values (1);
insert into people values (2);
insert into people values (3);

insert into tags values (1, 'foo');
insert into tags values (2, 'bar');
insert into tags values (3, 'baz');

insert into taggings values (1, 1, 'Person', 1);
insert into taggings values (2, 2, 'Person', 1);
insert into taggings values (3, 1, 'Person', 2);
insert into taggings values (4, 2, 'Person', 2);
insert into taggings values (5, 3, 'Person', 2);

现在我想要例如每个被标记为 foobar 的人。在这个例子中就是 id 为 2 的人。

select p.id, array_agg(t.name) as tag_name
from
    people p
    inner join
    taggings g on p.id = g.taggable_id
    inner join
    tags t on g.tag_id = t.id
where g.taggable_type = 'Person'
group by p.id
having array['foo','bar']::text[] <@ array_agg(t.name)
;
 id |   tag_name    
----+---------------
  1 | {bar,foo}
  2 | {baz,bar,foo}