我问过similar questions yesterday关于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是否有一种不那么冗长的方式呢?
offtopic
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)
答案 0 :(得分: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;
其他细节:
使用LIMIT / OFFSET作为@ user272735指出。
SELECT *
,因为你摆脱了额外的列。您可以在申报时分配变量。
短类型名称。
删除了多余的括号。
我在查询中添加了一个表别名和表限定,在这种情况下不是必需的,但这是避免plpgsql函数中命名冲突的好习惯。
答案 1 :(得分:1)
PostgreSQL提供LIMIT and OFFSET,可用于限制结果集。 E.g。
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_
;
答案 2 :(得分:0)
我不是Postgres特定功能的导出,但在SQL中分页通常有点棘手。在ANSI SQL中,我通常会执行SELECT COUNT(*)FROM ...来确定结果集的大小,然后使用游标来获取用户想要的页面。您的查询计算每个页面的结果集的大小,这可能会变得低效。另请注意,添加新记录时结果集的大小可能会发生变化,因此页面可能无法正确对齐。