PL/Python 和 postgreSQL:返回多列表的最佳方法是啥?

Posted

技术标签:

【中文标题】PL/Python 和 postgreSQL:返回多列表的最佳方法是啥?【英文标题】:PL/Python & postgreSQL: What is the best way to return a table of many columns?PL/Python 和 postgreSQL:返回多列表的最佳方法是什么? 【发布时间】:2016-07-11 18:25:48 【问题描述】:

在 Pl/Python 中,“RETURNS setof”或“RETURNS table”子句用于返回类似于结构化数据的表。在我看来,必须提供每列的名称才能返回表。如果您有一个包含几列的表格,这很容易。但是,如果您有一个包含 200 列的表,那么最好的方法是什么?我必须输入所有列的名称(如下所示)还是有办法绕过它?任何帮助将非常感激。

以下是使用“RETURNS table”子句的示例。代码 sn-ps 在 postgres 中创建一个表 (mysales),填充它,然后使用 Pl/Python 获取它并返回列值。为简单起见,我只从表中返回 4 列。

DROP TABLE IF EXISTS mysales;

CREATE TABLE mysales (id int, year int, qtr int, day int, region
text)  DISTRIBUTED BY (id);

INSERT INTO mysales VALUES 
(1, 2014, 1,1, 'north america'),
(2, 2002, 2,2, 'europe'),
(3, 2014, 3,3, 'asia'),
(4, 2010, 4,4, 'north-america'),
(5, 2014, 1,5, 'europe'),
(6, 2009, 2,6, 'asia'),
(7, 2002, 3,7, 'south america');

DROP FUNCTION IF EXISTS myFunc02();
CREATE OR REPLACE FUNCTION myFunc02() 
RETURNS TABLE (id integer, x integer, y integer, s text) AS 
$$
rv = plpy.execute("SELECT * FROM mysales ORDER BY id", 5)
d  = rv.nrows()
return ( (rv[i]['id'],rv[i]['year'], rv[i]['qtr'], rv[i]['region'])
for i in range(0,d) ) 
$$ LANGUAGE 'plpythonu';

SELECT * FROM myFunc02();

#Here is the output of the SELECT statement:
1; 2014; 1;"north america" 
2; 2002; 2;"europe" 
3; 2014; 3;"asia" 
4; 2010; 4;"north-america" 
5; 2014; 1;"europe" 
6; 2009; 2;"asia" 
7; 2002; 3;"south america"

【问题讨论】:

DISTRIBUTED BY 仅适用于 Greenplum。 正确。谢谢。 【参考方案1】:

试试这个:

CREATE OR REPLACE FUNCTION myFunc02() 
RETURNS TABLE (like mysales) AS 
$$
rv = plpy.execute('SELECT * FROM mysales ORDER BY id;', 5)
d  = rv.nrows()
return rv[0:d]
$$ LANGUAGE 'plpythonu';

返回:

gpadmin=# SELECT * FROM myFunc02();                             
 id | year | qtr | day |    region
----+------+-----+-----+---------------
  1 | 2014 |   1 |   1 | north america
  2 | 2002 |   2 |   2 | europe
  3 | 2014 |   3 |   3 | asia
  4 | 2010 |   4 |   4 | north-america
  5 | 2014 |   1 |   5 | europe
(5 rows)

像 Greenplum 和 HAWQ 这样的 MPP 需要考虑的是争取将数据作为参数并返回结果的函数,而不是在函数本身中生成数据。每个段都执行相同的代码,因此偶尔会出现意想不到的副作用。

SETOF 变体更新:

CREATE TYPE myType AS (id integer, x integer, y integer, s text);

CREATE OR REPLACE FUNCTION myFunc02a() 
RETURNS SETOF myType AS 
$$

# column names of myType ['id', 'x', 'y', 's']
rv = plpy.execute("SELECT id, year as x, qtr as y, region as s FROM mysales ORDER BY id", 5)
d  = rv.nrows()

return rv[0:d]
$$ LANGUAGE 'plpythonu';

注意,要使用原始示例中的相同数据,我必须将每个列别名为myType 中的相应名称。此外,如果走这条路线,您将不得不枚举 mysales 的所有列 - 尽管您可能可以使用它来减轻枚举所有的一些手动工作名称/类型:

select string_agg(t.attname || ' ' || t.format_type || ', ') as columns  from 
(
SELECT a.attname,
  pg_catalog.format_type(a.atttypid, a.atttypmod),
  (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
   FROM pg_catalog.pg_attrdef d
   WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),
  a.attnotnull, a.attnum,
  a.attstorage ,
  pg_catalog.col_description(a.attrelid, a.attnum)
FROM pg_catalog.pg_attribute a
LEFT OUTER JOIN pg_catalog.pg_attribute_encoding e
ON   e.attrelid = a .attrelid AND e.attnum = a.attnum
WHERE a.attrelid = (SELECT oid FROM pg_class WHERE relname = 'mysales') AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
) t ;

返回:

                              columns
-------------------------------------------------------------------
 id integer, year integer, qtr integer, day integer, region text,
(1 row)

【讨论】:

像魔术一样工作!!谢谢你,凯尔!我知道诀窍必须是“退货”条款。为了完整起见,这是我的第二个问题:这个问题也可以使用'returns setof'来解决吗? 这里是带有“setof”的sn-ps: DROP TYPE IF EXISTS myType CASCADE; CREATE TYPE myType AS (i​​d integer, x integer, y integer, s text);创建或替换函数 myFunc() 返回 SETOF myType AS $$ return [ rv[i] for i in range(0,d)] $$ .... 我已经更新了答案以包含一种方法来完成我认为您所要求的内容。如果您喜欢其中一个或/两个解决方案,请将问题标记为已回答。 :-)

以上是关于PL/Python 和 postgreSQL:返回多列表的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL[9.4-9.6]——服务器管理

JPA 和 PostgreSQL:如何调用具有 void 返回类型的存储过程?

带有更新和选择语句的 PostgreSQL 返回表导致歧义

测试使用和返回 refcursor 的 PostgreSQL 函数

PostgreSQL函数如何返回数据集 [转]

PostgreSQL 调用函数返回带有表和附加列的记录集