【问题标题】:How do I pass in a table parameter to this function?如何将表参数传递给此函数?
【发布时间】:2015-06-30 20:43:37
【问题描述】:

我有一个这样组织的函数:

create function everything(waypoints waypoint)
  returns table(node int, xy text array) as $$
BEGIN
    create view results as ...

    return query (select * from results);
END;
$$ LANGUAGE plpgsql;

我有一个表,其中的参数以waypoint 数据类型的结构方式组织。此表本身不是明确的waypoint 类型。

该函数按应有的方式创建,但是,我无法通过像这样传入我的表来调用它:

select everything(waypoints);

select everything(select * from temp);

但它说后者在select 或附近有语法错误,而前者的列waypoints 不存在。

我该怎么做?

【问题讨论】:

  • 为什么不立即让everything 接受tempCREATE FUNCTION everything (waypoints temp) ... 等等。
  • 始终提供您的 Postgres 版本。你的问题有点不清楚。我是否正确理解您要将整个表行转换为预定义的复合行类型?

标签: postgresql casting plpgsql


【解决方案1】:

在 Postgres 9.4 中测试的所有内容。

Postgres 在处理 ROW 类型的语法上有一些弱点。您不能直接从表(别名)投射:

<strike>SELECT w::waypoint FROM waypoints w;</strike>
ERROR:  cannot cast type waypoints to waypoint

解决方案只有一步之遥:在子查询中分解行,然后强制转换。这样,列值被分解并直接包装到新类型中,而无需转换为 text 并返回。无需单独列出所有列,也无需创建自定义转换:

SELECT (w.*)::waypoint FROM (SELECT * FROM waypoints) w;

或更短:

SELECT w.*::waypoint FROM (TABLE waypoints) w;

或者更短,但是:

SELECT w::waypoint FROM (TABLE waypoints) w;

SQL Fiddle

在使用 30k 行和简单类型的快速测试中,这比投射到 text 并返回时要快 10 倍。如果您有(大)jsonb 列或任何复杂类型(与 text 的昂贵转换),那么差异会更大。

更重要的是,您不需要另一个自定义复合 (ROW) 类型。每个表都已将其行自动定义为类型。只需使用现有类型 waypoints 而不是 waypoint(如果可能的话)。那么你只需要:

SELECT w FROM waypoints w;

或者,例如:

SELECT everything(t) FROM temp t;  -- using type waypoints
SELECT everything(t::waypoint) FROM (TABLE temp) t;  -- using type waypoint

旁白:

  • 表没有“参数”,但有列。
  • 不是传递table parameter to this function,而是行值。这就是按名称传递表格的方式:

    您不能直接在 Postgres 中“传递整个表”作为参数,没有表变量。为此,您可以使用游标或临时表。

功能

你的函数有一个无效的类型声明,而且是不必要的复杂。我严重怀疑你想创建一个视图:

CREATE FUNCTION everything(_wp waypoint)  -- or use type waypoints
  RETURNS TABLE(node int, xy text[]) AS
$func$
BEGIN
   RETURN QUERY
   SELECT ...
END
$func$ LANGUAGE plpgsql;

text array 是无效语法,使用text[] 代替声明text 的数组。

而不是使用表/类型名称waypoints 作为函数参数名称,这会使您容易混淆错误。

如果您的案例与演示的一样简单,则只需使用简单的 SQL 函数:

CREATE FUNCTION everything(_wp waypoint)  -- or use type waypoints
  RETURNS TABLE(node int, xy text[]) AS
$func$
   SELECT ...
$func$ LANGUAGE sql;

不要引用语言名称。这是一个标识符。

【讨论】:

  • 嘿,这是一篇出色的文章,非常感谢。但是当我运行这个时:select everything(t.*::waypoint) from (table temp) t; I get: relation "_wp" 不存在`...为什么会这样?
  • @Louis93: _wp 是我的示例中的函数参数名称。看起来动态 SQL 出错了。由于函数体是你的秘密,我只能猜测。我建议您发布一个带有必要详细信息的新问题
  • 我已授予您最佳答案,因为它提供的信息最多。这是一个包含必要细节的新问题:stackoverflow.com/questions/31188822/… 期待您的意见。
【解决方案2】:

如果waypointtemp中的所有类型都可以转换为text,则可以序列化为text并从text反序列化:

SELECT  everything(temp::text::waypoint)
FROM    temp

但是,显式构造会更简洁:

SELECT  everything((col1, col2, col3, ...)::waypoint)
FROM    temp

或创建CAST

CREATE FUNCTION temp_to_waypoint (temp)
RETURNS waypoint
AS
$$
        SELECT  (col1, col2, col3, ...)::waypoint
$$
LANGUAGE 'sql';

CREATE CAST (temp AS waypoint) WITH FUNCTION temp_to_waypoint (test) AS IMPLICIT;

SELECT  everything(temp)
FROM    temp;

【讨论】:

  • 你的意思是 temp::text::waypoint 对吗?因为航路点是数据类型?
  • 另一个问题,不相关但我一直看到这个:cannot DROP TABLE "graph" because it is being used by active queries in this session 虽然此表用于生成结果,但它是在之后创建的我试图放下它。我该如何解决这个问题?
  • @Louis93:请将其作为单独的问题发布。
猜你喜欢
  • 2019-01-28
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 2015-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多