在PostgreSQL中使用存储过程动态传递数据库和表名
我正在在PostgreSQL中使用存储过程动态传递数据库和表名,postgresql,stored-procedures,Postgresql,Stored Procedures,我正在PostgreSQL中创建一个存储过程,它将首先根据'ID'检查给定表中是否存在数据。如果是,则将其移动到其他表中,并在给定表名中插入最新记录。我编写了一个存储过程,我尝试使用硬编码的值,它可以根据我的需要工作,但是当我尝试使它成为通用的,即创建变量,然后将这些变量传递到查询中时,它会抛出一个错误。我参考了下面的,因此链接了,并且能够修改我的存储过程: 下面是我的存储过程: CREATE OR REPLACE PROCEDURE compareDups(ab integer, b js
PostgreSQL
中创建一个存储过程,它将首先根据'ID'
检查给定表中是否存在数据。如果是,则将其移动到其他表中,并在给定表名中插入最新记录。我编写了一个存储过程,我尝试使用硬编码的值,它可以根据我的需要工作,但是当我尝试使它成为通用的,即创建变量,然后将这些变量传递到查询中时,它会抛出一个错误。我参考了下面的,因此链接了,并且能够修改我的存储过程:
下面是我的存储过程:
CREATE OR REPLACE PROCEDURE compareDups(ab integer, b json, tablename varchar)
AS $$
DECLARE
actualTableName varchar := 'testing.'||tablename;
histTableName varchar:= actualTableName ||'_hist';
job_id Integer:=0;
BEGIN --<<<< HERE
EXECUTE 'SELECT id FROM '||actualTableName||' WHERE id =$1' INTO job_id USING ab;
-- if there is data for id in the table then perform below operations
IF job_id IS NOT NULL THEN
EXECUTE FORMAT('INSERT INTO %I as select * from %L where id = $1',histTableName,actualTableName) USING ab;
EXECUTE FORMAT('DELETE FROM %I where id = $1',actualTableName) USING ab;
EXECUTE FORMAT('INSERT INTO %I values($1,$2)',actualTableName) USING ab,b;
-- if id is not present then create a new record in the actualTable
ELSE
EXECUTE FORMAT('INSERT INTO %I values($1,$2)',actualTableName) USING ab,b;
END IF;
END; --<<<< END HERE
$$
LANGUAGE plpgsql;
我在这里遗漏了什么?所以,我想回答我自己的问题,也许它能帮助像我这样的人。我可以通过修改actualtablename
字符串来修复上面的代码,我也在这里设置了schema name
。因此,我在过程中添加了一个SET
语句,用于在需要执行预期操作的地方设置模式名称,这对我来说很有效
CREATE OR REPLACE PROCEDURE compareDups(ab integer, b json, tablename varchar)
AS $$
DECLARE
actualTableName varchar := tablename;
histTableName varchar:= actualTableName ||'_hist';
job_id Integer:=0;
BEGIN --<<<< HERE
SET search_path to testing; -- Set the schema name
EXECUTE 'SELECT id FROM '||actualTableName||' WHERE id =$1' INTO job_id USING ab;
-- if there is data for id in the table then perform below operations
IF job_id IS NOT NULL THEN
EXECUTE FORMAT('INSERT INTO %I select * from %I where id = $1',histTableName,actualTableName) USING ab;
EXECUTE FORMAT('DELETE FROM %I where id = $1',actualTableName) USING ab;
EXECUTE FORMAT('INSERT INTO %I values($1,$2)',actualTableName) USING ab,b;
-- if id is not present then create a new record in the actualTable
ELSE
EXECUTE FORMAT('INSERT INTO %I values($1,$2)',actualTableName) USING ab,b;
END IF;
END; --<<<< END HERE
$$
LANGUAGE plpgsql;
您缺少的是“testing.sampletesting_hist”应该是“testing”。“sampletesting_hist”也是无效的“testing.sampletesting”。标识符需要双引号。是的,我知道了:)您没有对过程
名称进行模式限定,因此它是在搜索路径
的第一个模式中创建的。在过程中设置搜索路径仅在过程内部有效。显式优于隐式如果您希望将对象指定给架构,则以这种方式命名,例如my_schema.compareDups。或者SET search\u path
是否紧跟在CREATE
之前?您的意思是我应该在创建过程之前指定SET search\u path命令,以便在该架构下创建?是的。虽然更好的选择是创建或替换过程测试。比较(…)
,那么就没有猜测了。是的,让我试试这个。谢谢@Adrian;)
CREATE OR REPLACE PROCEDURE compareDups(ab integer, b json, tablename varchar)
AS $$
DECLARE
actualTableName varchar := tablename;
histTableName varchar:= actualTableName ||'_hist';
job_id Integer:=0;
BEGIN --<<<< HERE
SET search_path to testing; -- Set the schema name
EXECUTE 'SELECT id FROM '||actualTableName||' WHERE id =$1' INTO job_id USING ab;
-- if there is data for id in the table then perform below operations
IF job_id IS NOT NULL THEN
EXECUTE FORMAT('INSERT INTO %I select * from %I where id = $1',histTableName,actualTableName) USING ab;
EXECUTE FORMAT('DELETE FROM %I where id = $1',actualTableName) USING ab;
EXECUTE FORMAT('INSERT INTO %I values($1,$2)',actualTableName) USING ab,b;
-- if id is not present then create a new record in the actualTable
ELSE
EXECUTE FORMAT('INSERT INTO %I values($1,$2)',actualTableName) USING ab,b;
END IF;
END; --<<<< END HERE
$$
LANGUAGE plpgsql;
set search_path to public;
call compareDups(12,'{"name":"CTTT"}','sampletesting');