use*_*380 17 postgresql types dynamic-sql plpgsql hstore
使用PostgreSQL,第一条记录的表中的列值存储在记录变量中.例如:让变量为:recordvar
recordvar.columnname
给出指定列名的值.我将columname在变量中定义:
var := columnname
在地方columnname,如果我与变量如更换recordvar.var,这是行不通的.
请让我知道如何处理这种情况.以下是示例代码:
CREATE OR REPLACE FUNCTION getrowdata(id numeric, table_name character varying)
RETURNS SETOF void AS
$BODY$ 
DECLARE
srowdata record;
reqfield character varying;
value numeric;
BEGIN
RAISE NOTICE 'id: %',id; 
reqfield:= 'columnname';
EXECUTE 'select * from datas.'||table_name||' WHERE id = '||id into srowdata;
RAISE NOTICE 'srowdata: %',srowdata; 
RAISE NOTICE 'srowdatadata.columnname: %',srowdata.columnname;
value:= srowdata.reqfield;
RAISE NOTICE 'value: %',value;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
Erw*_*ter 21
使用这个虚拟表
CREATE TEMP TABLE foo (id int, my_num numeric);
INSERT INTO foo VALUES (1, 12.34)
首先,我简化并清理了你的例子:
删除了一些与问题无关的噪音.
RETURNS SETOF void几乎没有意义.我RETURNS void改用了.
我只是为了简单text而使用而不是character varying.
当使用动态SQL,你必须要防范SQL注入,我使用format()与%I在这种情况下.还有其他方法.
基本问题是SQL对类型和标识符非常严格.您正在使用动态表名称以及记录的动态字段名称 - 原始示例中的匿名记录.Pl/pgSQL没有很好的处理能力.Postgres不知道匿名记录里面有什么.只有在将记录分配给众所周知的类型后才能引用单个字段.
这里是一个密切相关的问题,试图建立与动态名称记录的字段:
如何设置复合变量字段的值,使用动态SQL
CREATE OR REPLACE FUNCTION getrowdata1(table_name text, id int)
  RETURNS void AS
$func$ 
DECLARE
   srowdata record;
   reqfield text := 'my_num';   -- assigning at declaration time for convenience
   value    numeric;
BEGIN
RAISE NOTICE 'id: %', id; 
EXECUTE format('SELECT * FROM %I WHERE id = $1', table_name)
USING  id
INTO   srowdata;
RAISE NOTICE 'srowdata: %', srowdata;
RAISE NOTICE 'srowdatadata.my_num: %', srowdata.my_num;
/* This does not work, even with dynamic SQL
EXECUTE format('SELECT ($1).%I', reqfield)
USING srowdata
INTO value;
RAISE NOTICE 'value: %', value;
*/
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT * from getrowdata1('foo', 1);
评论部分会引发异常:
无法识别记录数据类型中的列"my_num":SELECT*from getrowdata(1,'foo')
hstore您需要为此安装附加模块hstore.每个数据库一次:
CREATE EXTENSION hstore;
然后所有人都可以这样工作:
CREATE OR REPLACE FUNCTION getrowdata2(table_name text, id int)
  RETURNS void AS
$func$ 
DECLARE
   hstoredata hstore;
   reqfield   text := 'my_num';
   value      numeric;
BEGIN
RAISE NOTICE 'id: %', id; 
EXECUTE format('SELECT hstore(t) FROM %I t WHERE id = $1', table_name)
USING  id
INTO   hstoredata;
RAISE NOTICE 'hstoredata: %', hstoredata;
RAISE NOTICE 'hstoredata.my_num: %', hstoredata -> 'my_num';
value := hstoredata -> reqfield;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT * from getrowdata2('foo', 1);
替代方案无需安装其他模块
由于您在记录变量中选择了整行,因此每个定义都有一个定义良好的类型.用它.关键词是多态类型.
CREATE OR REPLACE FUNCTION getrowdata3(_tbl anyelement, id int)
  RETURNS void AS
$func$ 
DECLARE
   reqfield text := 'my_num';
   value    numeric;
BEGIN
RAISE NOTICE 'id: %', id; 
EXECUTE format('SELECT * FROM %s WHERE id = $1', pg_typeof(_tbl))
USING  id
INTO   _tbl;
RAISE NOTICE '_tbl: %', _tbl;
RAISE NOTICE '_tbl.my_num: %', _tbl.my_num;
EXECUTE 'SELECT ($1).' || reqfield   -- requfield must be SQLi-safe or escape
USING _tbl
INTO  value;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT * from getrowdata3(NULL::foo, 1);
我(ab-)在这里使用输入参数_tbl有三个目的:  
本相关答案中的更多解释(最后一章):
重构PL/pgSQL函数以返回各种SELECT查询的输出
| 归档时间: | 
 | 
| 查看次数: | 19038 次 | 
| 最近记录: |