在plpgsql中,返回复合类型的集合而不进行强制转换?

时间:2019-06-17 15:54:54

标签: postgresql plpgsql

这可行,但是我需要强制转换(::name_value_pair)在我看来有点难看。有没有铸模的方法吗?

create type name_value_pair as (name text, value text);

create or replace function test1()
   returns setof name_value_pair
as $$
begin
    return next ROW('email', 'foo@example.com')::name_value_pair;
    return next ROW('user_id', 'abc123')::name_value_pair;
    return;
end;
$$ language plpgsql;

这是没有强制转换的错误。怎么不知道它是text?我以为用引号引起来的字符串文字是text,除非您将其转换为其他文字。

psql: ERROR:  returned record type does not match expected record type
DETAIL:  Returned type unknown does not match expected type text in column 1.
CONTEXT:  PL/pgSQL function test1() line 4 at RETURN NEXT

选择:

=> select * from test1();
  name   |      value      
---------+-----------------
 email   | foo@example.com
 user_id | abc123

我正在使用PostgreSQL 12 beta。

2 个答案:

答案 0 :(得分:2)

函数中的问题是ROW构造函数“先罢工”,创建了两个 unknown 值的复合类型,对此没有隐式类型转换。

5种方法,无需使用显式强制转换

1。。仍在使用预定义的复合/行类型,并使用显式详细的语法(大部分是受教育的)。子选择将未知类型默认为text ,然后将它们组合为ROW类型:

CREATE OR REPLACE FUNCTION test1()
  RETURNS SETOF name_value_pair AS
$func$
BEGIN
   RETURN NEXT (SELECT t FROM (SELECT 'email', 'foo@example.com') t);
   RETURN NEXT (SELECT t FROM (SELECT 'user_id', 'abc123') t);
END
$func$  LANGUAGE plpgsql IMMUTABLE;

SELECT * FROM test1();

2。。改用RETURNS TABLERETURN QUERY。无需形成复合类型,而让函数本身完成最后一步:

CREATE OR REPLACE FUNCTION test2()
  RETURNS TABLE (name text, value text) AS
$func$
BEGIN
   RETURN QUERY SELECT 'email', 'foo@example.com';
   RETURN QUERY SELECT 'user_id', 'abc123';
END
$func$  LANGUAGE plpgsql IMMUTABLE;

SELECT * FROM test2();

3。或仍使用复合类型来定义返回类型。可能更适合您:

CREATE OR REPLACE FUNCTION test3()
  RETURNS SETOF name_value_pair AS
$func$
BEGIN
   RETURN QUERY SELECT 'email', 'foo@example.com';
   RETURN QUERY SELECT 'user_id', 'abc123';
END
$func$  LANGUAGE plpgsql IMMUTABLE;

SELECT * FROM test3();

4。就这么简单,普通SQL函数中的普通VALUES expression更短,更快:

CREATE OR REPLACE FUNCTION test4()
  RETURNS SETOF name_value_pair AS
$func$
VALUES
  ('email', 'foo@example.com')
, ('user_id', 'abc123');
$func$  LANGUAGE sql IMMUTABLE;

SELECT * FROM test4();

5。必须是PL / pgSQL:

CREATE OR REPLACE FUNCTION test5()
  RETURNS SETOF name_value_pair AS
$func$
BEGIN
RETURN QUERY VALUES
  ('email', 'foo@example.com')
, ('user_id', 'abc123');
END
$func$  LANGUAGE plpgsql IMMUTABLE;

SELECT * FROM test5();

db <>提琴here

Postgres 10 中添加了针对函数的标量返回值的从unknowntext的隐式转换。 Postgres 9.6或更早的版本更加严格,对于替代项1-3会产生类似的错误。(仅功能4和5.在任何Postgres版本中均可使用。)

ERROR: structure of query does not match function result type
DETAIL: Returned type unknown does not match expected type text in column 1.

人们可能会争论ROW类型仍然严格的行为是对该更新还是设计的疏忽。我猜可能是有理由的。

相关:

答案 1 :(得分:1)

这里的问题是像'email'这样的字符串常量的类型为unknown,而不是类型为text

您可以这样重写示例:

create type name_value_pair as (name text, value text);

create or replace function test1()
   returns setof name_value_pair
as $$
begin
    return next ROW('email'::text, 'foo@example.com'::text);
    return next ROW('user_id'::text, 'abc123'::text);
    return;
end;
$$ language plpgsql;