如何从函数 return setof 记录?
How to return setof records from function?
我正在尝试创建一个将 return 记录集的函数。我想按如下方式使用函数:
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;
$$
我应该改变什么?
您可以更改 return 语句:
...
-- It's wrong
-- RETURN QUERY SELECT result;
RETURN NEXT result; -- that's good
...
但是,函数 returning "record" 需要列定义列表,因此您必须在每个查询中添加它:
SELECT city_name FROM set_city(1, 1, 'ExampleName')
AS (id int, country_id int, city_name text);
事实上,函数 return 是类型 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 *;
我正在尝试创建一个将 return 记录集的函数。我想按如下方式使用函数:
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;
$$
我应该改变什么?
您可以更改 return 语句:
...
-- It's wrong
-- RETURN QUERY SELECT result;
RETURN NEXT result; -- that's good
...
但是,函数 returning "record" 需要列定义列表,因此您必须在每个查询中添加它:
SELECT city_name FROM set_city(1, 1, 'ExampleName')
AS (id int, country_id int, city_name text);
事实上,函数 return 是类型 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 *;