如何从PL/pgSQL 函数中返回多行数据
2016-10-05 17:14
204 查看
PgSQL 自7.3起支持SRF( Set Returning Func. 集合返回函数) 配合有一些新的函数权限选项,
使 schema 的设置更灵活性。SRF 除了手册里提到的内置函数 generate_series generate_subscript 外,自定义函数也可返回集合。 下面示例摘译自 PgSQL wiki :PL/PgSQL如何返回多行结果
我们从处理简单表单函数说起。
首先我们看一个简单的SQL函数返回现有表中的 rowtype
其返回类型为 setof employee 即返回由 employee 各行组成的行集合,
其主体采用简单SQL语句,生成输出的行。
SRF 可以在查询中代替 FROM 中的 表 或 子查询 。
例如用函数返回所有id>2的聘员只要:
例如: 部门列表及其中所有聘员的薪水,
要返回现有记录类型,你需要创建一个虚构类型来保存输出的数据,
例如:
和名为 totalsalary 的 bigint 组成,我们可以让函数返回此类型的集合:
这次我们用 SQL 和 PL/pgSQL 来分别实现这个函数:
返回的行由函数体中的 group by 查询决定。
PL/pgSQL 版本稍复杂,首先变量 r 被声明为 rowtype holder 。用此变量保存行函数体中的查询结果,函数主体对 group by 查询的结果循环执行,r 依次被赋值为结果中的各行,循环体中采用了新的return形式 'return next' 即将结果追加到返回的集合中,但不会造成函数返回。目前 PL/pgSQL 的 SRF 函数在全部结果生成完毕前不会返回。如果集合很大会写入硬盘。此限制未来的版本中也许会改变。
新函数的使用与之前相同,
PL/pgSQL 函数还可以对结果进行运算,只返回某些结果。
例如:要计算部门运营成本:部门总薪资 70,000 以上的开销是 75%, 其他为 50%,
返回薪资+开销>100,000的部门的部门id。
因为本次只需要返回高成本部门的 department id
函数返回一个整数集合 (department id) 而非之前的复合类型。
注意本次 return next 没有返回记录 r 而只有 departmentid,
如果需要同时返回 薪资总额与开销之和,
前面声明中可以定义为 return setof holder 这里使用 return next r;
以上函数返回的复合类型使用的前提是返回的类型与函数的 return 声明中的相同。
如果不同,SQL版本在创建时会报错,PL/pgSQL 版本在运行中会出现错。
但如果结果中的类型只能在运行中确定该怎么办?
此时你可以声明 return setof record 以返回复合类型的集合,
返回的类型可以调用时设置。例如我们要创建一个函数返回指定表中的所有行:
调用此函数时比之前的要稍复杂,查询中需要指定函数返回的数据。
PostgreSQL 对 SRF函数 的处理与子查询相似,语法上与为子查询中别名的设定相似。
由一个 INT 和一个 TEXT 组成。于是我们告诉PgSQL,结果dept 为别名,
包含一个名为 deptid 的整数和 deptname 的文本。
最后我们试试完全用 PL/pgSQL函数生成数据。让我们从最简单的做起:
写一个函数,接收返回1到任意数间的所有数,以及这个他们的二倍。
我们先写一个以预定义类型的为内部和返回类型的版本。
将1到参数间的每个值,赋给 num 和 doublenum
然后 return next r 将结果加入输出集合的队列中;
用 record 类型可以实现通用效果,免去函数外的类型声明,
不过做起来会更复杂而且需要多一次 select 调用。
类似返回多个结果的还有 动态 SQL 查询语句
(PREPARE STATEMENT... + EXECUTE...INTO...USING + DEALLOCATE PREPARE)
通过返回 指针 也可以实现返回多行结果。
https://www.postgresql.org/docs/current/static/ecpg-dynamic.html
使 schema 的设置更灵活性。SRF 除了手册里提到的内置函数 generate_series generate_subscript 外,自定义函数也可返回集合。 下面示例摘译自 PgSQL wiki :PL/PgSQL如何返回多行结果
我们从处理简单表单函数说起。
create table department(id int primary key, name text); create table employee(id int primary key, name text, salary int, departmentid int references department); insert into department values (1, 'Management'); insert into department values (2, 'IT'); insert into employee values (1, 'John Smith', 30000, 1); insert into employee values (2, 'Jane Doe', 50000, 1); insert into employee values (3, 'Jack Jackson', 60000, 2);SRF 可以返回的数据类型可以是现有表中定义过的 rowtype 或通用的 record 类型。
首先我们看一个简单的SQL函数返回现有表中的 rowtype
create function GetEmployees() returns setof employee as 'select * from employee;' language 'sql';这个非常简单的函数直接返回 employee 中的所有行:
其返回类型为 setof employee 即返回由 employee 各行组成的行集合,
其主体采用简单SQL语句,生成输出的行。
SRF 可以在查询中代替 FROM 中的 表 或 子查询 。
例如用函数返回所有id>2的聘员只要:
select * from GetEmployees() where id > 2;很好,但要返回更复杂的数据怎么办?
例如: 部门列表及其中所有聘员的薪水,
要返回现有记录类型,你需要创建一个虚构类型来保存输出的数据,
例如:
create type holder as (departmentid int, totalsalary int8);这里创建了新的复合类型 holder 由名为 departmentid 的 int
和名为 totalsalary 的 bigint 组成,我们可以让函数返回此类型的集合:
这次我们用 SQL 和 PL/pgSQL 来分别实现这个函数:
create function SqlDepartmentSalaries() returns setof holder as ' select departmentid, sum(salary) as totalsalary from GetEmployees() group by departmentid ' language 'sql';
create or replace function PLpgSQLDepartmentSalaries() returns setof holder as ' declare r holder%rowtype; begin for r in select departmentid, sum(salary) as totalsalary from GetEmployees() group by departmentid loop return next r; end loop; return; end ' language 'plpgsql';SQL的版本与之前的很相像,返回由 holder (int, int8) 类型定义的 rowtype,
返回的行由函数体中的 group by 查询决定。
PL/pgSQL 版本稍复杂,首先变量 r 被声明为 rowtype holder 。用此变量保存行函数体中的查询结果,函数主体对 group by 查询的结果循环执行,r 依次被赋值为结果中的各行,循环体中采用了新的return形式 'return next' 即将结果追加到返回的集合中,但不会造成函数返回。目前 PL/pgSQL 的 SRF 函数在全部结果生成完毕前不会返回。如果集合很大会写入硬盘。此限制未来的版本中也许会改变。
新函数的使用与之前相同,
select * from PLpgSQLDepartmentSalaries();
PL/pgSQL 函数还可以对结果进行运算,只返回某些结果。
例如:要计算部门运营成本:部门总薪资 70,000 以上的开销是 75%, 其他为 50%,
返回薪资+开销>100,000的部门的部门id。
create or replace function ExpensiveDepartments() returns setof int as ' declare r holder%rowtype; begin for r in select departmentid, sum(salary) as totalsalary from GetEmployees() group by departmentid loop if (r.totalsalary > 70000) then r.totalsalary := CAST(r.totalsalary * 1.75 as int8); else r.totalsalary := CAST(r.totalsalary * 1.5 as int8); end if; if (r.totalsalary > 100000) then return next r.departmentid; end if; end loop; return; end ' language 'plpgsql';比较一下本次与之前 PLpgSQLDepartmentSales() 的区别。
因为本次只需要返回高成本部门的 department id
函数返回一个整数集合 (department id) 而非之前的复合类型。
if (r.totalsalary > 70000) then r.totalsalary := CAST(r.totalsalary * 1.75 as int8); else r.totalsalary := CAST(r.totalsalary * 1.5 as int8); end if;然后判断 totalsalary 是否大于 100,000 如果为真,则返回识别符
if (r.totalsalary > 100000) then return next r.departmentid; end if;
注意本次 return next 没有返回记录 r 而只有 departmentid,
如果需要同时返回 薪资总额与开销之和,
前面声明中可以定义为 return setof holder 这里使用 return next r;
以上函数返回的复合类型使用的前提是返回的类型与函数的 return 声明中的相同。
如果不同,SQL版本在创建时会报错,PL/pgSQL 版本在运行中会出现错。
但如果结果中的类型只能在运行中确定该怎么办?
此时你可以声明 return setof record 以返回复合类型的集合,
返回的类型可以调用时设置。例如我们要创建一个函数返回指定表中的所有行:
create or replace function GetRows(text) returns setof record as ' declare r record; begin for r in EXECUTE ''select * from '' || $1 loop return next r; end loop; return; end ' language 'plpgsql';
调用此函数时比之前的要稍复杂,查询中需要指定函数返回的数据。
PostgreSQL 对 SRF函数 的处理与子查询相似,语法上与为子查询中别名的设定相似。
select * from GetRows('Department') as dept(deptid int, deptname text);我们将 Department 作为参数传入,结果应该与 Department 表的一般记录相同,
由一个 INT 和一个 TEXT 组成。于是我们告诉PgSQL,结果dept 为别名,
包含一个名为 deptid 的整数和 deptname 的文本。
最后我们试试完全用 PL/pgSQL函数生成数据。让我们从最简单的做起:
写一个函数,接收返回1到任意数间的所有数,以及这个他们的二倍。
我们先写一个以预定义类型的为内部和返回类型的版本。
create type numtype as (num int, doublenum int); create or replace function GetNum(int) returns setof numtype as ' declare r numtype%rowtype; i int; begin for i in 1 .. $1 loop r.num := i; r.doublenum := i*2; return next r; end loop; return; end ' language 'plpgsql';函数非常简单,声明中 r 为名为 numtype 的自定义 rowtype 。
将1到参数间的每个值,赋给 num 和 doublenum
然后 return next r 将结果加入输出集合的队列中;
用 record 类型可以实现通用效果,免去函数外的类型声明,
不过做起来会更复杂而且需要多一次 select 调用。
类似返回多个结果的还有 动态 SQL 查询语句
(PREPARE STATEMENT... + EXECUTE...INTO...USING + DEALLOCATE PREPARE)
通过返回 指针 也可以实现返回多行结果。
https://www.postgresql.org/docs/current/static/ecpg-dynamic.html
相关文章推荐
- pl/sql函数如何返回多行数据
- SqlServer 如何将查询出的多行数据拼成一个字符串返回
- ajax返回函数json数据如何取值问题
- 如何从 PL/SQL 存储函数返回数组
- Dynamic动态数据类型(例如如何设置IQueryable的类型为函数返回的类型?? )
- 如何从 PL/SQL 存储函数返回数组
- 如何从文本文件读取数据到二维数组,如何在函数处理后返回二维数组的示例
- 返回数据库数据的存储过程函数(3个参数)(SQL Server)
- freopen()函数的使用及如何返回控制台。
- 在C中如何使函数返回数组
- SharePoint:DataView如何绑定Web Service返回的主从表数据集
- [C/C++]如何解读返回函数指针的函数声明
- 在C#中如何在函数参数中返回结构数组?
- 关于C#间接继承的一些思考:如何修改继承函数的返回值类型
- SqlServer:根据指定分隔符,把传入字符串分隔处理后,返回数据表,函数功能类似.NET的string.Split()
- c++函数调用的返回值在函数调用栈上如何传递给调用者(返回大对象时)
- AJAX获取数据成功后的返回数据如何声明成全局变量
- 如何点击按钮弹出新窗口,输入数据后返回并刷新页面?
- 【坑】使用 RxJS 的 of() 函数来模拟从服务器返回数据
- ORACLE 函数处理的数据返回值过长 character string buffer too small