PLPGSQL 函数 return 的问题,涉及 uuid
Problem with PLPGSQL function return, uuid involved
我想分配序列中的序列号以及自动生成的 uuid。我的 table 看起来像
CREATE TABLE master_serialnumbers
(
uuident uuid PRIMARY KEY DEFAULT uuid_generate_v1(),
serno integer GENERATED ALWAYS AS IDENTITY UNIQUE,
requester varchar(20) NOT NULL
);
我现在可以使用
生成序列号
INSERT INTO master_serialnumbers(requester) VALUES ('XY')
RETURNING (uuident,serno,requester);
要自动执行此操作并生成包含多个序列号的块,我可以使用如下函数:
CREATE FUNCTION gen_serials_A(num_serials integer, req varchar(20))
RETURNS SETOF master_serialnumbers
AS $$
DECLARE
new_id uuid;
rr master_serialnumbers%ROWTYPE; -- or simply RECORD
tmpSQL TEXT;
BEGIN
RAISE NOTICE 'generate % serial numbers', num_serials;
CREATE TEMPORARY TABLE tmpIds (id uuid NOT NULL PRIMARY KEY);
FOR i IN 1..num_serials LOOP
RAISE NOTICE 'serno %', i;
INSERT INTO master_serialnumbers(space, requester) VALUES (spc, req)
RETURNING (uuident) INTO new_id;
INSERT INTO tmpIds(id) VALUES (new_id);
END LOOP;
FOR rr IN EXECUTE 'SELECT * FROM master_serialnumbers
WHERE uuident IN (SELECT id FROM tmpIds)' LOOP
RETURN NEXT rr;
END LOOP;
tmpSQL := 'DROP TABLE tmpIds';
EXECUTE tmpSQL;
RETURN;
END
$$ LANGUAGE plpgsql;
这确实有效,但将值存储在临时 table 中并有两个循环似乎很麻烦。所以我试着像这样缩短它:
CREATE FUNCTION gen_serials(num_serials integer, req varchar(20))
RETURNS SETOF master_serialnumbers
AS $$
DECLARE
rr master_serialnumbers%ROWTYPE;
BEGIN
RAISE NOTICE 'generate % serial numbers', num_serials;
FOR i IN 1..num_serials LOOP
RAISE NOTICE 'serno %', i;
INSERT INTO master_serialnumbers(requester) VALUES (req)
RETURNING (uuident,serno,requester) INTO rr;
RAISE NOTICE 'rr is %', rr;
RETURN NEXT rr;
END LOOP;
RETURN;
END
$$ LANGUAGE plpgsql;
– 但是 INSERT
抛出错误
invalid input syntax for type uuid: »(12345678-1234-1234-1234-123456789abc,1,A)«
将声明更改为 rr RECORD
现在会传递 INSERT
:
rr is ("(12345678-1234-1234-1234-123456789abc,1,A)")
ERROR: wrong record type supplied in RETURN NEXT
DETAIL: Returned type does not match expected type uuid in column 1.
好像都已经转成字符串了
并且将 return 类型也更改为 SETOF RECORD
会产生另一个错误:
ERROR: function with set result called in a context that cannot process set results
(德语错误信息由我翻译回英语,抱歉)。
知道这里发生了什么(没有发生)吗?也许我通过使用带有程序循环的函数来做这件事太啰嗦了?
To automate this and generate a block of several serial numbers, I can use a function
不要搞得这么复杂。使用像
这样的东西
INSERT INTO master_serialnumbers(requester)
VALUES ('XY', 'YZ', 'ZA')
RETURNING uuident, serno, requester;
或
INSERT INTO master_serialnumbers(requester)
SELECT UNNEST(ARRAY['XY', 'YZ', 'ZA']) -- useful for parameterised queries
RETURNING uuident, serno, requester;
或
INSERT INTO master_serialnumbers(requester)
SELECT 'XY'
FROM generate_series(1, 20) -- useful for arbitrary repetition of the same value
RETURNING uuident, serno, requester;
我想分配序列中的序列号以及自动生成的 uuid。我的 table 看起来像
CREATE TABLE master_serialnumbers
(
uuident uuid PRIMARY KEY DEFAULT uuid_generate_v1(),
serno integer GENERATED ALWAYS AS IDENTITY UNIQUE,
requester varchar(20) NOT NULL
);
我现在可以使用
生成序列号INSERT INTO master_serialnumbers(requester) VALUES ('XY')
RETURNING (uuident,serno,requester);
要自动执行此操作并生成包含多个序列号的块,我可以使用如下函数:
CREATE FUNCTION gen_serials_A(num_serials integer, req varchar(20))
RETURNS SETOF master_serialnumbers
AS $$
DECLARE
new_id uuid;
rr master_serialnumbers%ROWTYPE; -- or simply RECORD
tmpSQL TEXT;
BEGIN
RAISE NOTICE 'generate % serial numbers', num_serials;
CREATE TEMPORARY TABLE tmpIds (id uuid NOT NULL PRIMARY KEY);
FOR i IN 1..num_serials LOOP
RAISE NOTICE 'serno %', i;
INSERT INTO master_serialnumbers(space, requester) VALUES (spc, req)
RETURNING (uuident) INTO new_id;
INSERT INTO tmpIds(id) VALUES (new_id);
END LOOP;
FOR rr IN EXECUTE 'SELECT * FROM master_serialnumbers
WHERE uuident IN (SELECT id FROM tmpIds)' LOOP
RETURN NEXT rr;
END LOOP;
tmpSQL := 'DROP TABLE tmpIds';
EXECUTE tmpSQL;
RETURN;
END
$$ LANGUAGE plpgsql;
这确实有效,但将值存储在临时 table 中并有两个循环似乎很麻烦。所以我试着像这样缩短它:
CREATE FUNCTION gen_serials(num_serials integer, req varchar(20))
RETURNS SETOF master_serialnumbers
AS $$
DECLARE
rr master_serialnumbers%ROWTYPE;
BEGIN
RAISE NOTICE 'generate % serial numbers', num_serials;
FOR i IN 1..num_serials LOOP
RAISE NOTICE 'serno %', i;
INSERT INTO master_serialnumbers(requester) VALUES (req)
RETURNING (uuident,serno,requester) INTO rr;
RAISE NOTICE 'rr is %', rr;
RETURN NEXT rr;
END LOOP;
RETURN;
END
$$ LANGUAGE plpgsql;
– 但是 INSERT
抛出错误
invalid input syntax for type uuid: »(12345678-1234-1234-1234-123456789abc,1,A)«
将声明更改为 rr RECORD
现在会传递 INSERT
:
rr is ("(12345678-1234-1234-1234-123456789abc,1,A)")
ERROR: wrong record type supplied in RETURN NEXT
DETAIL: Returned type does not match expected type uuid in column 1.
好像都已经转成字符串了
并且将 return 类型也更改为 SETOF RECORD
会产生另一个错误:
ERROR: function with set result called in a context that cannot process set results
(德语错误信息由我翻译回英语,抱歉)。
知道这里发生了什么(没有发生)吗?也许我通过使用带有程序循环的函数来做这件事太啰嗦了?
To automate this and generate a block of several serial numbers, I can use a function
不要搞得这么复杂。使用像
这样的东西INSERT INTO master_serialnumbers(requester)
VALUES ('XY', 'YZ', 'ZA')
RETURNING uuident, serno, requester;
或
INSERT INTO master_serialnumbers(requester)
SELECT UNNEST(ARRAY['XY', 'YZ', 'ZA']) -- useful for parameterised queries
RETURNING uuident, serno, requester;
或
INSERT INTO master_serialnumbers(requester)
SELECT 'XY'
FROM generate_series(1, 20) -- useful for arbitrary repetition of the same value
RETURNING uuident, serno, requester;