如何在 PL/pgSQL 函数中引用参数?
How to reference parameters inside a PL/pgSQL function?
我遇到一个问题,当我尝试通过名称直接引用参数时,我在函数被调用后取回了文字值。谁能帮我解决如何在这里使用参数值的问题?
CREATE OR REPLACE FUNCTION dbo.reset_sequence(
tablename text,
columnname text,
sequence_name text)
RETURNS void AS
$BODY$
DECLARE
BEGIN
IF( (SELECT MAX( columnname ) ) < (SELECT min_value FROM dbo.tablename) )
THEN
-- EXECUTE 'SELECT setval( ' || sequence_name || ', (SELECT min_value FROM dbo.' || sequence_name ||')';
ELSE
-- EXECUTE 'SELECT setval( ' || sequence_name || ', ' || '(SELECT MAX("' || columnname || '") FROM dbo."' || tablename || '")' || '+1)';
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
编辑:我遇到的问题更具体地与 EXECUTE
命令之外的语法有关。另一个解决方案并没有真正帮助我。
在研究了另一个主题后,我正在尝试另一个解决方案,但仍然遇到问题。
CREATE OR REPLACE FUNCTION dbo.reset_sequence(
tablename text,
columnname text,
sequence_name text)
RETURNS void AS
$BODY$
DECLARE
_maxVal int;
_minVal int;
BEGIN
EXECUTE format('SELECT MAX( ''' || columnname || ''' ) FROM ' || schema_name || '."' || tablename || '"')
INTO _maxVal;
EXECUTE format('SELECT min_value FROM ' || schema_name || '."' || sequence_name || ''' ')
INTO _minVal;
IF( maxVal < _minVal)
THEN
-- EXECUTE 'SELECT setval( ' || sequence_name || ', (SELECT min_value FROM dbo.' || sequence_name ||')';
ELSE
-- EXECUTE 'SELECT setval( ' || sequence_name || ', ' || '(SELECT MAX("' || columnname || '") FROM dbo."' || tablename || '")' || '+1)';
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
这个语法有效,但是当我调用该函数时出现错误,它无法将 EXECUTE
语句存储为整数,它似乎返回列的名称,而不是该列中的最大值。
如果先使用 EXECUTE .. INTO
将 EXECUTE
语句的结果存储到临时值中,则可以在 IF
语句中使用它们。例如:
DECLARE
max_column_value int;
BEGIN
EXECUTE 'SELECT MAX(' || columnname || ') FROM dbo."' || tablename || '"'
INTO max_column_value;
IF max_column_value < 1000 THEN
...
如果 columnname
是 'col'
并且 tablename
是 'tbl'
,这应该等同于:
IF (SELECT MAX(col) FROM dbo."tbl") < 100 THEN
没有解释该函数究竟应该做什么,代码也含糊不清。据我了解,这是函数的目的:
将给定模式中的给定序列重置为相同模式的给定 table 中给定列的最大值 - 或给定的最小值序列如果应该更大。
尚不清楚架构 dbo
是否也涉及。将 dbo
保持在循环中,这个 应该 工作:
CREATE OR REPLACE FUNCTION reset_sequence(
sch text, -- schema_name
tbl text, -- table_name
col text, -- column_name
seq text -- sequence_name -- all unquoted and case-SENSITIVE!
) RETURNS void AS
$func$
DECLARE
_max_val int;
_min_val int;
BEGIN
EXECUTE format('SELECT MAX(%I) FROM %I.%I', col, sch, tbl)
INTO _max_val;
EXECUTE format('SELECT min_value FROM %I.%I', sch, seq)
INTO _min_val;
IF _max_val < _min_val THEN
EXECUTE format($$SELECT setval('%1$I.%2$I', min_value, false) FROM dbo.%2$I;$$
, sch, seq);
ELSE
EXECUTE format($$SELECT setval('%I.%I', max(%I)) FROM dbo.%I;$$
, sch, seq, col, tbl);
END IF;
END
$func$ LANGUAGE plpgsql;
可以简化为:
CREATE OR REPLACE FUNCTION pg_temp.reset_sequence(sch text, tbl text, col text, seq text)
RETURNS void AS
$func$
DECLARE
_found bool;
BEGIN
EXECUTE format('SELECT true FROM %1$I.%2$I
HAVING MAX(%3$I) < (SELECT min_value FROM %1$I.%4$I)'
, sch, tbl, col, seq)
INTO _found;
IF _found THEN
EXECUTE format($$SELECT setval('%1$I.%2$I', min_value, false) FROM dbo.%2$I;$$
, sch, seq);
ELSE
EXECUTE format($$SELECT setval('%I.%I', max(%I)) FROM dbo.%I;$$
, sch, seq, col, tbl);
END IF;
END
$func$ LANGUAGE plpgsql;
如果使用 dbo
只是我怀疑的错字,更简单:
CREATE OR REPLACE FUNCTION pg_temp.reset_sequence(sch text, tbl text, col text, seq text)
RETURNS void AS
$func$
BEGIN
EXECUTE format($$
SELECT setval('%1$I.%4$I', GREATEST(s.min, t.max + 1), false) -- now we need + 1
FROM (SELECT MAX(%3$I) FROM %1$I.%2$I) t(max)
, (SELECT min_value FROM %1$I.%4$I) s(min)
$$, sch, tbl, col, seq);
END
$func$ LANGUAGE plpgsql;
各种问题
您正在以荒谬的方式将 format()
与纯字符串连接混合在一起。请务必read the manual on format()
,然后再继续。
变量 schema_name
未定义。我添加了另一个函数参数来传递它。
odd 您在最后的两个 setval()
调用中使用架构 dbo
。 "dbo"
也是 SQL 服务器的典型标识符,但在 Postgres 中不是。可能是另一个错误或故意的?
变量 maxVal
未定义。应该是_maxVal
。我在简化版本中完全删除了该变量。
对于 setval()
,您不需要 + 1
,因为默认情况下返回的下一个值会递增。 Example in the manual:
SELECT setval('foo', 42); -- Next nextval will return 43
另一方面,如果您想从序列的最开头开始,请使用:
SELECT setval('my_sequence', min_value, <b>false</b>)
更多解释
只有 运行 这样的查询才干净:
SELECT setval('my_sequence', min_value) FROM other_sequence;
.. 因为 SEQUENCE
的 table 保证恰好有 1 行 .
我遇到一个问题,当我尝试通过名称直接引用参数时,我在函数被调用后取回了文字值。谁能帮我解决如何在这里使用参数值的问题?
CREATE OR REPLACE FUNCTION dbo.reset_sequence(
tablename text,
columnname text,
sequence_name text)
RETURNS void AS
$BODY$
DECLARE
BEGIN
IF( (SELECT MAX( columnname ) ) < (SELECT min_value FROM dbo.tablename) )
THEN
-- EXECUTE 'SELECT setval( ' || sequence_name || ', (SELECT min_value FROM dbo.' || sequence_name ||')';
ELSE
-- EXECUTE 'SELECT setval( ' || sequence_name || ', ' || '(SELECT MAX("' || columnname || '") FROM dbo."' || tablename || '")' || '+1)';
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
编辑:我遇到的问题更具体地与 EXECUTE
命令之外的语法有关。另一个解决方案并没有真正帮助我。
在研究了另一个主题后,我正在尝试另一个解决方案,但仍然遇到问题。
CREATE OR REPLACE FUNCTION dbo.reset_sequence(
tablename text,
columnname text,
sequence_name text)
RETURNS void AS
$BODY$
DECLARE
_maxVal int;
_minVal int;
BEGIN
EXECUTE format('SELECT MAX( ''' || columnname || ''' ) FROM ' || schema_name || '."' || tablename || '"')
INTO _maxVal;
EXECUTE format('SELECT min_value FROM ' || schema_name || '."' || sequence_name || ''' ')
INTO _minVal;
IF( maxVal < _minVal)
THEN
-- EXECUTE 'SELECT setval( ' || sequence_name || ', (SELECT min_value FROM dbo.' || sequence_name ||')';
ELSE
-- EXECUTE 'SELECT setval( ' || sequence_name || ', ' || '(SELECT MAX("' || columnname || '") FROM dbo."' || tablename || '")' || '+1)';
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
这个语法有效,但是当我调用该函数时出现错误,它无法将 EXECUTE
语句存储为整数,它似乎返回列的名称,而不是该列中的最大值。
如果先使用 EXECUTE .. INTO
将 EXECUTE
语句的结果存储到临时值中,则可以在 IF
语句中使用它们。例如:
DECLARE
max_column_value int;
BEGIN
EXECUTE 'SELECT MAX(' || columnname || ') FROM dbo."' || tablename || '"'
INTO max_column_value;
IF max_column_value < 1000 THEN
...
如果 columnname
是 'col'
并且 tablename
是 'tbl'
,这应该等同于:
IF (SELECT MAX(col) FROM dbo."tbl") < 100 THEN
没有解释该函数究竟应该做什么,代码也含糊不清。据我了解,这是函数的目的:
将给定模式中的给定序列重置为相同模式的给定 table 中给定列的最大值 - 或给定的最小值序列如果应该更大。
尚不清楚架构 dbo
是否也涉及。将 dbo
保持在循环中,这个 应该 工作:
CREATE OR REPLACE FUNCTION reset_sequence(
sch text, -- schema_name
tbl text, -- table_name
col text, -- column_name
seq text -- sequence_name -- all unquoted and case-SENSITIVE!
) RETURNS void AS
$func$
DECLARE
_max_val int;
_min_val int;
BEGIN
EXECUTE format('SELECT MAX(%I) FROM %I.%I', col, sch, tbl)
INTO _max_val;
EXECUTE format('SELECT min_value FROM %I.%I', sch, seq)
INTO _min_val;
IF _max_val < _min_val THEN
EXECUTE format($$SELECT setval('%1$I.%2$I', min_value, false) FROM dbo.%2$I;$$
, sch, seq);
ELSE
EXECUTE format($$SELECT setval('%I.%I', max(%I)) FROM dbo.%I;$$
, sch, seq, col, tbl);
END IF;
END
$func$ LANGUAGE plpgsql;
可以简化为:
CREATE OR REPLACE FUNCTION pg_temp.reset_sequence(sch text, tbl text, col text, seq text)
RETURNS void AS
$func$
DECLARE
_found bool;
BEGIN
EXECUTE format('SELECT true FROM %1$I.%2$I
HAVING MAX(%3$I) < (SELECT min_value FROM %1$I.%4$I)'
, sch, tbl, col, seq)
INTO _found;
IF _found THEN
EXECUTE format($$SELECT setval('%1$I.%2$I', min_value, false) FROM dbo.%2$I;$$
, sch, seq);
ELSE
EXECUTE format($$SELECT setval('%I.%I', max(%I)) FROM dbo.%I;$$
, sch, seq, col, tbl);
END IF;
END
$func$ LANGUAGE plpgsql;
如果使用 只是我怀疑的错字,更简单:dbo
CREATE OR REPLACE FUNCTION pg_temp.reset_sequence(sch text, tbl text, col text, seq text)
RETURNS void AS
$func$
BEGIN
EXECUTE format($$
SELECT setval('%1$I.%4$I', GREATEST(s.min, t.max + 1), false) -- now we need + 1
FROM (SELECT MAX(%3$I) FROM %1$I.%2$I) t(max)
, (SELECT min_value FROM %1$I.%4$I) s(min)
$$, sch, tbl, col, seq);
END
$func$ LANGUAGE plpgsql;
各种问题
您正在以荒谬的方式将
format()
与纯字符串连接混合在一起。请务必read the manual onformat()
,然后再继续。变量
schema_name
未定义。我添加了另一个函数参数来传递它。 odd 您在最后的两个setval()
调用中使用架构dbo
。"dbo"
也是 SQL 服务器的典型标识符,但在 Postgres 中不是。可能是另一个错误或故意的?变量
maxVal
未定义。应该是_maxVal
。我在简化版本中完全删除了该变量。对于
setval()
,您不需要+ 1
,因为默认情况下返回的下一个值会递增。 Example in the manual:SELECT setval('foo', 42); -- Next nextval will return 43
另一方面,如果您想从序列的最开头开始,请使用:
SELECT setval('my_sequence', min_value, <b>false</b>)
更多解释
只有 运行 这样的查询才干净:
SELECT setval('my_sequence', min_value) FROM other_sequence;
.. 因为
SEQUENCE
的 table 保证恰好有 1 行 .