boo*_*biq 7 postgresql dynamic-sql plpgsql functions
我有一个存储过程,RETURNS SETOF ct_custom_type我在里面做
RETURN QUERY EXECUTE 'some dynamic query'
Run Code Online (Sandbox Code Playgroud)
我想这样做:如果这个“动态查询”返回 >= 10 行,我想返回它们,但如果它只返回 < 10 行,我不想返回任何东西(空集ct_custom_type)。
我试过:
RETURN QUERY EXECUTE 'some dynamic query'
GET DIAGNOSTICS variable = ROW_COUNT;
IF variable < 10 THEN
# I don't know what to do here or how to accomplish this
END IF;
Run Code Online (Sandbox Code Playgroud)
如果我RETURN QUERY SELECT 0, 0, ''::text;在IF块中执行(因为ct_custom_type是 的复合类型(integer, integer, text),它只是将这个“空行”添加到先前的查询结果中,但在这种情况下我不想返回任何内容,我可以这样做RETURN;,但它会返回先前的结果,我想丢弃它。
我有这样的:
EXECUTE 'dynamic query';
GET DIAGNOSTICS variable = ROW_COUNT;
IF variable >= 10 THEN
RETURN QUERY EXECUTE 'dynamic query';
END IF;
Run Code Online (Sandbox Code Playgroud)
它有效,但我不想两次执行此查询。
您可以按照以下方式做一些事情:
test=> CREATE OR REPLACE FUNCTION temptabl(cnt integer)
RETURNS SETOF integer AS
$body$
BEGIN
CREATE TEMPORARY TABLE tmp_container ON COMMIT DROP AS
SELECT a
FROM generate_series(1, cnt) t(a);
IF (SELECT count(1) FROM tmp_container) > 5
THEN
RETURN QUERY SELECT a FROM tmp_container;
END IF;
END;
$body$
LANGUAGE plpgsql;
test=> SELECT * FROM temptabl(4);
temptabl
----------
(0 rows)
test=> SELECT * FROM temptabl(6);
temptabl
----------
1
2
3
4
5
6
(6 rows)
Run Code Online (Sandbox Code Playgroud)
这样您只需执行一次原始查询。所有其他语句都适用于临时表。
RETURN NEXT并且RETURN QUERY实际上并不从函数返回——它们只是将零或更多行附加到函数的结果集中。然后继续执行 PL/pgSQL 函数中的下一条语句。随着连续RETURN NEXT或RETURN QUERY命令的执行,结果集被建立起来。finalRETURN应该没有参数,导致控制退出函数(或者你可以让控制到达函数的末尾)。
EXCEPTION替代所以你可以通过提高 an 来取消操作,EXCEPTION客户端不会得到任何行。
不会比这更便宜:
CREATE OR REPLACE FUNCTION f_min_records(min_ct integer = 10) -- default minimum 10
RETURNS SETOF tbl AS
$func$
DECLARE
row_ct int;
BEGIN
RETURN QUERY EXECUTE 'some dynamic query (matching return type)';
GET DIAGNOSTICS row_ct = ROW_COUNT;
IF row_ct < min_ct THEN
RAISE EXCEPTION 'Only % rows! Requested minimum was %.', row_ct, min_ct;
END IF;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
调用(默认最少 10 行):
SELECT * FROM f_min_records_wrapper();
Run Code Online (Sandbox Code Playgroud)
我们在 ( get_available_flightid())的手册中包含了一个代码示例。
EXCEPTION据我所知,防止返回集实际返回的唯一方法是引发异常。如果您也不想引发异常,那么您对当前的 plpgsql 有点不满意。
如果在同一个函数中捕获EXCEPTION,仍会返回结果集。
我试图用嵌套块解决它但失败了。似乎对返回集没有任何影响。
但是您可以将函数调用嵌套在外部函数中并在那里捕获异常。这可以正常工作:
除了上面的扩展功能:
CREATE OR REPLACE FUNCTION f_min_records(min_ct integer = 10) -- default minimum 10
RETURNS SETOF t AS
$func$
DECLARE
row_ct int;
BEGIN
RETURN QUERY EXECUTE 'SELECT * from t'; -- some dynamic query (matching return type)
GET DIAGNOSTICS row_ct = ROW_COUNT;
IF row_ct < min_ct THEN
RAISE SQLSTATE 'BRRRR' -- 5 ASCII chars
USING MESSAGE = format('Only %s rows! Requested minimum was %s.', row_ct, min_ct);
END IF;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
创建一个包装函数,您实际调用它:
CREATE OR REPLACE FUNCTION f_min_records_wrapper(min_ct integer = 10)
RETURNS SETOF t AS
$func$
BEGIN
RETURN QUERY
SELECT * from f_min_records(min_ct);
EXCEPTION
WHEN SQLSTATE 'BRRRR' THEN
RAISE NOTICE '%', SQLERRM; -- optionally pass error msg
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
称呼:
SELECT * FROM f_min_records_wrapper(17);
Run Code Online (Sandbox Code Playgroud)
与deszo 的答案相同的基本思想,但避免单独计数,以及其他功能:
CREATE OR REPLACE FUNCTION f_temptbl(min_ct integer = 10)
RETURNS SETOF t AS
$func$
DECLARE
row_ct int;
BEGIN
DROP TABLE IF EXISTS _temptbl; -- for mult. calls in 1 transaction
CREATE TEMP TABLE _temptbl (LIKE t) ON COMMIT DROP; -- match RETURNS type
EXECUTE 'INSERT INTO _temptbl SELECT * FROM t'; -- text with dyn SQL
GET DIAGNOSTICS row_ct = ROW_COUNT;
IF row_ct >= min_ct THEN
RETURN QUERY TABLE _temptbl;
END IF;
END;
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
取消返回集的命令会很棒:
RETURN CANCEL;
Run Code Online (Sandbox Code Playgroud)
或者甚至可以选择“回滚”行数(默认为全部):
RETURN CANCEL 10;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
27385 次 |
| 最近记录: |