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_id問題は、出力が次のようになるため、一意の の数に基づいて制限したいことです。

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

SQL はそれぞれとコンボtag_idに対して行を返しますが、s を出力用の配列にグループ化する方法に注意してください。tag_idimage_id

だから、私が言うときlimit 100、私はそれを100のユニークな に適用したいimage_id.

4

2 に答える 2

2

たぶん、各行に1つの画像を配置する必要がありますか? それが機能する場合は、次のことができます。

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を結合します。準結合
を 使用して images_tags の条件を満たし、かっこが正しくなるように注意してください。EXISTS

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 に答える