2017-06-18 92 views
0

我想创建一个函数,它将返回setof记录。我想使用的功能如下:如何从函数返回setof记录?

SELECT city_name FROM set_city(1, 1, 'ExampleName'); 

我的功能:

CREATE OR REPLACE FUNCTION set_city(_city_id integer, _country_id integer, _city_name varchar) 
RETURNS SETOF RECORD 
LANGUAGE plpgsql 
as $$ 

DECLARE 
     result record; 

BEGIN 
     IF EXISTS (SELECT 1 FROM geo_cities gc WHERE gc.id = _city_id) 
     THEN 
       UPDATE geo_cities 
       SET country_id = _country_id, city_name = _city_name 
       WHERE id = _city_id 
       RETURNING * INTO result; 
     ELSE 
       INSERT INTO geo_cities(id, country_id, city_name) 
       VALUES (_city_id, _country_id, _city_name) 
       RETURNING * INTO result; 
     END IF; 
     -- It's wrong 
     RETURN QUERY SELECT result; 
END; 
$$ 

我应该怎么改?

回答

1

你可以改变返回语句:

... 
     -- It's wrong 
     -- RETURN QUERY SELECT result; 
     RETURN NEXT result; -- that's good 
... 

然而,需要返回“记录”功能的字段定义列表,所以你必须将它添加在每个查询:

SELECT city_name FROM set_city(1, 1, 'ExampleName') 
    AS (id int, country_id int, city_name text); 

事实上,函数返回类型为geo_cities的单行,而您不需要setof

DROP FUNCTION set_city(_city_id integer, _country_id integer, _city_name varchar); 

CREATE OR REPLACE FUNCTION set_city(_city_id integer, _country_id integer, _city_name varchar) 
RETURNS geo_cities 
LANGUAGE plpgsql 
as $$ 
DECLARE 
     result geo_cities; 
BEGIN 
     IF EXISTS (SELECT 1 FROM geo_cities gc WHERE gc.id = _city_id) 
     THEN 
       UPDATE geo_cities 
       SET country_id = _country_id, city_name = _city_name 
       WHERE id = _city_id 
       RETURNING * INTO result; 
     ELSE 
       INSERT INTO geo_cities(id, country_id, city_name) 
       VALUES (_city_id, _country_id, _city_name) 
       RETURNING * INTO result; 
     END IF; 
     RETURN result; 
END; 
$$; 

SELECT city_name FROM set_city(1, 1, 'ExampleName'); 

请注意,您可以在单个SQL语句中获得相同的功能:

INSERT INTO geo_cities(id, country_id, city_name) 
VALUES (1, 1, 'ExampleName') 
ON CONFLICT (id) DO UPDATE SET 
    country_id = excluded.country_id, 
    city_name = excluded.city_name 
RETURNING *;