如何访问嵌套用户定义类型的字段?

时间:2017-01-23 03:16:33

标签: sql postgresql

如何在嵌套时访问用户定义类型的字段? 当我用点符号尝试它时失败了:

ERROR:  "v_zoo.bear_object.animal_name" is not a known variable
LINE 8:  v_zoo.bear_object.animal_name='Mishka';

例如,我如何" 编译"这段代码?

sqls $ cat animal.sql 
DROP TYPE IF EXISTS zoo_t CASCADE;
CREATE TYPE zoo_t AS (
    wolf_object         animal_t,
    bear_object         animal_t

);
DROP TYPE IF EXISTS animal_t CASCADE;
CREATE TYPE animal_t AS (
    animal_id           integer,
    animal_color        varchar,
    animal_name         varchar
);
CREATE OR REPLACE FUNCTION animal_func()
RETURNS void AS $$
DECLARE
    v_animal        animal_t;
    v_zoo           zoo_t;
BEGIN
    v_animal.animal_name:='Chupacabras';
    v_zoo.bear_object.animal_name='Mishka';
END;
$$ LANGUAGE PLPGSQL;

尝试运行它:

sqls $ psql dev < animal.sql 
DROP TYPE
CREATE TYPE
NOTICE:  drop cascades to 2 other objects
DETAIL:  drop cascades to composite type zoo_t column wolf_object
drop cascades to composite type zoo_t column bear_object
DROP TYPE
CREATE TYPE
ERROR:  "v_zoo.bear_object.animal_name" is not a known variable
LINE 8:  v_zoo.bear_object.animal_name='Mishka';
         ^
 sqls $ 

1 个答案:

答案 0 :(得分:3)

看起来像PL / PgSQL缺陷。在普通的SQL中,您可以使用

执行此操作
test=> WITH x(zoo) AS (VALUES(ROW( ROW(1, 'red', 'panda')::animal_t, ROW(2, 'black', 'bear')::animal_t )::zoo_t))
SELECT (zoo).bear_object.animal_color FROM x;
 animal_color 
--------------
 black
(1 row)

但是pl / pgsql不接受相同的形式:

test=> CREATE OR REPLACE FUNCTION animal_func()
RETURNS void AS $$
DECLARE
    v_animal        animal_t;
    v_zoo           zoo_t;
BEGIN
    v_animal.animal_name:='Chupacabras';
    (v_zoo).bear_object.animal_name='Mishka';
END;
$$ LANGUAGE PLPGSQL;
ERROR:  syntax error at or near "("
LINE 8:     (v_zoo).bear_object.animal_name='Mishka';

所以我认为这是一个错误/疏忽/限制。考虑在pgsql-bugs上提高它。

您可以通过将其解压缩到temp var,修改它并再次存储来访问它,但它的效率非常低。

CREATE OR REPLACE FUNCTION animal_func()
RETURNS void AS $$
DECLARE
    v_animal        animal_t;
    v_zoo           zoo_t;
BEGIN
    v_animal := v_zoo.bear_object;
    v_animal.animal_name := 'Mishka';
    v_zoo.bear_object := v_animal;
END;
$$ LANGUAGE PLPGSQL;

那说:我不建议使用plpgsql来做这种伪OO的东西。 SQL不是OO,并且不能与嵌套的用户定义复合类型一起使用。修改内容效率非常低 - SQL中的大多数内容都是不可变的,因此在修改值时会生成新的副本。迭代更改和程序代码工作得非常糟糕。

你应该寻求与集合和关系一起工作。在一次传递中构造新值,不要迭代地修改它们并逐个设置字段。使用关系而不是让一个对象包含另一个对象。

另外,删除匈牙利表示法。啊。