1

我有一张这样的桌子:

create table images (
    image_id serial primary key,
    user_id int references users(user_id),
    date_created timestamp with time zone
);

然后,我有一个标签表,用于显示图像可以具有的标签:

create table images_tags (
    images_tag_id serial primary key,
    image_id int references images(image_id),
    tag_id int references tags(tag_id)       
);

为了得到我想要的结果,我运行这样的查询:

select image_id,user_id,tag_id from images left join images_tags using(image_id)
where (?=-1 or user_id=?)
and (?=-1 or tag_id in (?, ?, ?, ?)) --have up to 4 tag_ids to search for
order by date_created desc limit 100;

问题是,我想根据唯一image_ids 的数量进行限制,因为我的输出将如下所示:

{"images":[
    {"image_id":1, "tag_ids":[1, 2, 3]},
    ....
]}

请注意我如何将tag_ids 分组到一个数组中以进行输出,即使 SQL 为每个tag_idimage_id组合返回一行。

所以,当我说 时limit 100,我希望它适用于 100 个独特image_id的 s。

4

2 回答 2

2

也许你应该在每一行放一张图片?如果可行,您可以执行以下操作:

select image_id, user_id, string_agg(cast(tag_id as varchar(2000)), ',') as tags
from images left join
     images_tags
     using (image_id)
where (?=-1 or user_id=?) and
      (?=-1 or tag_id in (?, ?, ?, ?)) --have up to 4 tag_ids to search for
group by image_id, user_id
order by date_created desc
limit 100;

如果这不起作用,请使用 CTE:

with cte as (
      select image_id, user_id, tag_id,
             dense_rank() over (order by date_created desc) as seqnum
      from images left join
           images_tags
           using (image_id)
      where (?=-1 or user_id=?) and
            (?=-1 or tag_id in (?, ?, ?, ?)) --have up to 4 tag_ids to search for
    )
select *
from cte
where seqnum <= 100
order by seqnum;
于 2014-05-20T22:09:00.183 回答
1

首先选择 100 个符合条件的图像,然后加入 images_tags。
使用EXISTS半连接来满足 images_tags 上的条件,并注意使括号正确。

SELECT i.*, t.tag_id
FROM  (
   SELECT i.image_id, i.user_id
   FROM   images i
   WHERE (? = -1 OR i.user_id = ?)
   AND   (? = -1 OR EXISTS (
      SELECT 1
      FROM   images_tags t
      WHERE  t.image_id = i.image_id
      AND    t.tag_id IN (?, ?, ?, ?)
      ))
   ORDER  BY i.date_created DESC
   LIMIT  100
   ) i
LEFT   JOIN images_tags t
            ON t.image_id = i.image_id
           AND (? = -1 OR t.tag_id in (?, ?, ?, ?)) -- repeat condition

这应该比具有窗口函数和 CTE 的解决方案更快。
用 测试性能EXPLAIN ANLAYZE。一如既往地运行几次以预热缓存。

于 2014-05-20T22:18:56.933 回答