0

私は昨日、postgressについて、そしてそれがselectステートメントの結果の形からタイプを推測できるかどうかについて同様の質問をしました。

今日、クエリから結果セットを返したいのですが、これは私が機能することがわかったクエリです:

DROP TYPE IF EXISTS topic_result_entry CASCADE;
CREATE TYPE topic_result_entry AS
(
    id            INTEGER,  
    last_post_at  TIMESTAMP WITHOUT TIME ZONE,
    is_sticky     BOOLEAN,
    is_poll       BOOLEAN,
    has_prefix    BOOLEAN,
    prefix        CHARACTER VARYING,
    title         CHARACTER VARYING,
    post_count    INTEGER,
    started_by    INTEGER,
    started_at    TIMESTAMP WITHOUT TIME ZONE
);

CREATE OR REPLACE FUNCTION get_paginated_topics(
    forum_id_ INTEGER, category_id_ INTEGER, page_number_ INTEGER, topics_per_page_ INTEGER)
RETURNS SETOF topic_result_entry as $$
DECLARE
    zero_based_index INTEGER;
    lower_offset INTEGER;
    upper_offset INTEGER;

BEGIN                    
    zero_based_index := page_number_ -1;
    lower_offset := zero_based_index * topics_per_page_;
    upper_offset := ( (topics_per_page_ * page_number_) + 1 );               

    RETURN query
    select id,last_post_at, is_sticky, is_poll, 
           has_prefix, prefix, title,post_count, 
           started_by, started_at 
    from (
        select row_number() OVER(ORDER by last_post_at desc) as rn, * 
        from forum_topics where category_id = category_id_ and forum_id= forum_id_
    ) as foo
    where rn > lower_offset and rn < upper_offset;
END;
$$ LANGUAGE plpgsql;

結果セットの形状は、selectのパラメータリスト+ソーステーブルのスキーマ定義から推測できます。

Q1。9.1にはいくつかの糖衣構文がありますか?そうでない場合、これはロードマップにありますか?

Q2これを行うためのより冗長な方法はありますか?

オフトピック

select id,last_post_at, is_sticky, is_poll, 
       has_prefix, prefix, title,post_count, 
       started_by, started_at 
from (
    select row_number() OVER(ORDER by last_post_at desc) as rn, * 
    from forum_topics where category_id = 72
) as foo
where rn>0 and rn<22

QUERY PLAN  
Subquery Scan on foo  (cost=0.00..492.20 rows=28 width=60)  
  Filter: ((foo.rn > 0) AND (foo.rn < 22))  
  ->  WindowAgg  (cost=0.00..409.42 rows=5519 width=156)    
        ->  Index Scan using forum_topics_last_post_at_idx1 on forum_topics  (cost=0.00..326.63 rows=5519 width=156)    
              Filter: (category_id = 72)
4

3 に答える 3

2

糖衣?私はあなたのためにいくつかを手に入れました。

もしも ...

結果セットの形状は、ソーステーブルのスキーマ定義から推測できます[...]

...その後、はるかに単純化することができます。PostgreSQLでは、テーブル定義が同じ名前のタイプを自動的に定義します。


CREATE OR REPLACE FUNCTION get_paginated_topics(
    _forum_id int, _category_id int, _page_number int, _topics_per_page int)
RETURNS SETOF forum_topics AS
$BODY$
DECLARE
   _lower_offset  int := (_page_number - 1) * _topics_per_page;
   _upper_offset  int := _topics_per_page * _page_number + 1;
BEGIN

   RETURN QUERY
   SELECT *
   FROM   forum_topics f
   WHERE  f.category_id = category_id_
   AND    f.forum_id = forum_id_
   ORDER  BY f.last_post_at DESC
   LIMIT  _lower_offset
   OFFSET _upper_offset;

END;
$BODY$ LANGUAGE plpgsql;

その他の情報:

  • @ user272735が指摘したように、LIMIT/OFFSETを使用します。

    • 次にSELECT *、余分な列を削除したので、を使用できます。
  • 宣言時に変数を割り当てることができます。

  • 短いタイプ名。

  • 冗長な括弧を削除しました。

  • クエリにテーブルエイリアスとテーブル修飾を追加しました。これはこの場合は必要ありませんが、plpgsql関数での名前の競合を避けるための良い習慣です。

于 2012-07-20T02:50:49.157 に答える
1

PostgreSQLは、結果セットを制限するために使用できるLIMITとOFFSETを提供します。例えば

select id, last_post_at, is_sticky, is_poll, 
       has_prefix, prefix, title, post_count, 
       started_by, started_at 
  from forum_topics
 where category_id = category_id_ and forum_id = forum_id_
 order by id
 limit topics_per_page_
offset (page_number_ - 1) * topics_per_page_
;
于 2012-07-19T19:20:17.203 に答える
0

私はPostgres固有の機能のエクスポートではありませんが、SQLでは一般的にページ付けが少し注意が必要です。ANSI SQLでは、通常、SELECT COUNT(*)FROM ...を実行して結果セットのサイズを決定し、カーソルを使用してユーザーが必要とするページを取得します。クエリは各ページの結果セットのサイズを計算しますが、これは非効率になる可能性があります。また、新しいレコードが追加されると結果セットのサイズが変わる可能性があるため、ページが互いに適切に整列しない可能性があることにも注意してください。

于 2012-07-19T18:27:57.723 に答える