将现有类型用作“列定义列表”

时间:2018-07-19 20:02:48

标签: postgresql

我已经创建了一个预先存在的类型,并希望使用它为另一个查询定义列定义列表。似乎它具有相同的信息,但是我无法设法找到一种允许使用它代替列定义列表的语法。

从本质上讲,我正在尝试在所使用的枢轴上尽可能进行DRY(不要重复自己)。因此,我要做的一件事是使用pg_classpg_attribute表从预定义类型中提取我需要的“类别名称”。然后,我想使用相同的类型来标识crosstab SELECT的输出。

这是设置:

CREATE EXTENSION IF NOT EXISTS tablefunc;
CREATE TABLE test1 (id INT, k TEXT, val TEXT, PRIMARY KEY (id, k));
INSERT INTO test1 (id, k, val) VALUES
    (1, 'abc', 'Value for abc'),
    (1, 'xyz', 'Value for xyz'),
    (2, 'xyz', 'Value for xyz'),
    (2, 'def', 'Value for def'),
    (1, 'ghi', 'Value for ghi'),
    (1, 'notused', 'unused'),
    (2, 'notused', 'unused2'),
    (2, 'someother', 'other2');

--- Type to be returned
CREATE TYPE pv1_type AS (id INT, xyz TEXT, abc TEXT, def TEXT, ghi TEXT);

--- Pull category field names from the type above for use in crosstab(TEXT, TEXT)
CREATE FUNCTION CatNames(_typename TEXT, _attmin INT) RETURNS SETOF TEXT AS $$
    SELECT attname::TEXT
    FROM pg_attribute
    WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = _typename)
          AND attnum >= _attmin;
$$ LANGUAGE SQL;

CREATE FUNCTION pv1()
    RETURNS SETOF pv1_type AS
$func$
    SELECT * FROM crosstab(
        $$SELECT id, k, val FROM test1 ORDER BY id$$,
        $$SELECT CatNames('pv1_type', 2)$$) AS (id INT, xyz TEXT, abc TEXT, def TEXT, ghi TEXT);
$func$ LANGUAGE SQL;

这很好用,可以满足我的要求

# SELECT * FROM pv1();
 id |      xyz      |      abc      |      def      |      ghi
----+---------------+---------------+---------------+---------------
  1 | Value for xyz | Value for abc |               | Value for ghi
  2 | Value for xyz |               | Value for def |
(2 rows)

但是,请注意,我在crosstab的输出中使用的列定义列表与pv1_type的列相同,在此我重复一遍。我没有某种方法可以简单地使用该类型来定义输出,而不是重复列列表吗?

类似SELECT * FROM crosstab(...) AS pv1_type;(不起作用)吗?

可以用对此替代方法的调用替换crosstab调用,从而消除了提供列定义列表的要求:

CREATE FUNCTION pv1_crosstab(TEXT, TEXT) RETURNS SETOF pv1_type
  AS '$libdir/tablefunc', 'crosstab_hash' LANGUAGE c STABLE STRICT;

这可以解决问题,但是我的迁移框架没有授予我的用户创建C语言函数的权限,而且我不能轻易更改它。

0 个答案:

没有答案