在触发器函数中使用动态表名进行 INSERT

2024-05-08

我不确定如何实现类似以下的目标:

CREATE OR REPLACE FUNCTION fnJobQueueBEFORE() RETURNS trigger AS $$
    DECLARE
        shadowname varchar := TG_TABLE_NAME || 'shadow';
    BEGIN
        INSERT INTO shadowname VALUES(OLD.*);
        RETURN OLD;
    END;
$$
LANGUAGE plpgsql;

IE。将值插入具有动态生成名称的表中。
执行上面的代码会得到:

ERROR:  relation "shadowname" does not exist
LINE 1: INSERT INTO shadowname VALUES(OLD.*)

这似乎表明变量没有扩展/允许作为表名。我在 Postgres 手册中没有找到对此的引用。

我已经尝试过EXECUTE像这样:

  EXECUTE 'INSERT INTO ' || quote_ident(shadowname) || ' VALUES ' || OLD.*;

但没有运气:

ERROR:  syntax error at or near ","
LINE 1: INSERT INTO personenshadow VALUES (1,sven,,,)

The RECORD类型似乎丢失了:OLD.*似乎被转换为字符串并重新解析,导致各种类型问题(例如NULL值)。

有任何想法吗?


现代 PostgreSQL

format() https://www.postgresql.org/docs/current/functions-string.html#FUNCTIONS-STRING-OTHER有一种内置的方法来转义标识符。比以前更简单:

CREATE OR REPLACE FUNCTION foo_before()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format('INSERT INTO %I.%I SELECT $1.*'
                , TG_TABLE_SCHEMA, TG_TABLE_NAME || 'shadow')
   USING OLD;

   RETURN OLD;
END
$func$;

与一个VALUES https://www.postgresql.org/docs/current/sql-values.html表达也。

db<>fiddle
Old sqlfiddle http://sqlfiddle.com/#!17/ff78f/1

主要观点

  • Use format() https://www.postgresql.org/docs/current/functions-string.html#FUNCTIONS-STRING-OTHER or quote_ident() https://www.postgresql.org/docs/current/functions-string.html#FUNCTIONS-STRING-OTHER引用标识符(自动且仅在必要时),从而防御SQL注入 https://en.wikipedia.org/wiki/Sql_injection和简单的语法违规。
    这是必要的,即使有您自己的表名!
  • 架构限定表名。取决于当前search_path setting https://stackoverflow.com/a/9067777/939860否则,裸表名称可能会解析为不同模式中同名的另一个表。
  • Use EXECUTE用于动态 DDL 语句。
  • Pass values安全地与USING clause.
  • 查阅详细手册在 plpgsql 中执行动态命令 https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN.
  • 注意RETURN OLD;在触发器函数中需要一个触发器BEFORE DELETE. 手册中有详细说明。 https://www.postgresql.org/docs/current/trigger-definition.html

你得到错误信息在你几乎成功的版本中,因为OLD is 不可见 inside EXECUTE。如果您想像您尝试的那样连接分解行的各个值,则必须使用以下方法准备每个列的文本表示quote_literal()以保证语法有效。你还必须know预先列名来处理它们或查询系统目录 - 这违背了您拥有简单的动态触发函数的想法......

我的解决方案避免了所有这些并发症。也简化了一点。

PostgreSQL 9.0 或更早版本

format()尚不可用,所以:

CREATE OR REPLACE FUNCTION foo_before()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
    EXECUTE 'INSERT INTO ' || quote_ident(TG_TABLE_SCHEMA)
                    || '.' || quote_ident(TG_TABLE_NAME || 'shadow')
                    || ' SELECT $1.*'
    USING OLD;

    RETURN OLD;
END
$func$;

Related:

  • 如何在 PostgreSQL 8.2 中动态使用 TG_TABLE_NAME? https://stackoverflow.com/questions/7519044/how-to-dynamically-use-tg-table-name-in-postgresql-8-2/7617533#7617533
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在触发器函数中使用动态表名进行 INSERT 的相关文章

  • 当我使用 IS NOT NULL 时无法创建 MySQL TRIGGER

    CREATE TRIGGER b I O AFTER UPDATE ON book FOR EACH ROW BEGIN IF OLD status IS NOT NULL AND NEW status IS NOT NULL AND NE
  • 使用 java 中的准备好的语句插入自定义 SQL 类型

    我有一些自定义类型 它们基本上都是枚举 以下是它们的外观示例 CREATE TYPE card suit AS ENUM spades clubs hearts diamonds 我在 Java 中有一些准备好的语句 看起来像这样 Setu
  • Python SQLAlchemy 用户身份验证失败

    我尝试使用 SQLAlchemy 连接 PostgreSQL 数据库 我创建了一个像这样的新角色 首先 我使用以下命令登录到 postgres 帐户 sudo i u postgres 接下来 发出命令 createuser interac
  • 设置 MySQL 触发器

    我听说过有关触发器的事情 我有几个问题 什么是触发器 我该如何设置它们 除了典型的 SQL 内容之外 是否还应该采取任何预防措施 触发器允许您在发生某些事件 例如 插入表 时在数据库中执行某个功能 我无法具体评论mysql 注意事项 触发器
  • PostgreSQL ISOLATION LEVEL 生效的时间似乎是在第一次 SELECT 之后

    我正在运行 PostgreSQL 9 5 3 我试图理解为什么我看到下面两个例程之间的行为差 异 我发现这种行为违反直觉 但可能有一个很好的理由 我只是想知道如果是的话那是什么 Setting ISOLATION LEVEL REPEATA
  • 如何使用准备好的语句在 postgresql 中插入带有时区的时间戳?

    我正在尝试使用准备好的语句将一个字符串插入到数据库的带有时区字段的时间戳中 其中包括日期 时间和时区 问题是 Timestamp valueof 函数没有考虑字符串包含的时区 因此会导致错误 接受的格式是 yyyy m m d d hh m
  • 节点 PostgreSQL 客户端查询超时

    我正在使用节点包pg对于 postgres here https github com brianc node postgres npm i pg var pg require pg 我正在查询一个不属于我的大型集群 在某些条件下可能会失败
  • 使用临时表替换 WHERE IN 子句

    我让用户输入我需要在表中查询的值列表 该列表可能非常大 并且长度在编译时未知 而不是使用WHERE IN 我认为使用临时表并对其执行联接会更有效 我在另一个SO问题中读到了这个建议 目前找不到它 但会在找到时进行编辑 要点是这样的 CREA
  • 连接到 Docker Postgres 容器连接超时

    所以我所做的是 docker run d e POSTGRES USER user e POSTGRES PASSWORD 456789 name admin service p 5432 5432 postgres 当我检查时docker
  • 如何手动设置auto_increment的下一个值?

    我手动向表中添加了一些行 并且还手动设置了 ID 自动增量 现在 当我尝试通过我的应用程序将新行添加到数据库表中时 我收到错误 创建的 ID 值已存在 如何手动设置下一个ID值 例如 在表中我必须有ID 那么如何告诉PostgreSQL 下
  • 如何将 iLike 运算符与 Sequelize 结合使用来进行不区分大小写的查询

    我使用 Sequelize 和 PostgreSQL 来管理我的数据库 我想执行不区分大小写的搜索查询 当我用谷歌搜索时 有人说我可以使用 iLike 运算符来做到这一点 我尝试以这种方式实现 var getRadiosByGenre fu
  • 如何获取 JDBC 中 UPDATE 查询影响的所有行?

    我有一项任务需要使用更新记录PreparedStatement 一旦记录被更新 我们知道更新查询返回计数 即受影响的行数 但是 我想要的不是计数 而是受更新查询影响的行作为响应 或者至少是受影响的行的 id 值列表 这是我的更新查询 UPD
  • MySQL 查询中的窗口函数

    有没有办法在 SELECT 查询本身中动态地使用 MySQL 查询中的窗口函数 我知道在 PostgreSQL 中这是可能的 例如 下面是 PostgreSQL 中的等效查询 SELECT c server ip c client ip s
  • 更新期间唯一索引违规

    我在更大的数据库中遇到了唯一索引违规 最初的问题发生在存储的 pl pgsql 函数中 我已经简化了一切以显示我的问题 我可以在一个相当简单的表格中重现它 CREATE TABLE public test id integer NOT NU
  • Rails 4 - 如何在开发中使用 sqlite3 以及在生产中使用 PostgreSQL 和 Heroku

    我正在尝试部署到 Heroku 但不能 因为默认的 sqlite3 服务器仍然存在 检测到 Heroku 不支持 sqlite3 gem https devcenter heroku com articles sqlite3 https d
  • ActiveRecord 查询,按关联排序,最后一个 has_many

    我试图列出所有Users by the created at最近创建的关联记录 通讯 列 到目前为止我所拥有的 User includes communications order communications created at IS
  • PostgreSQL 如何对字段上的 b 树索引执行 ORDER BY?

    我有一张桌子bsort CREATE TABLE bsort a int data text Here data可能不完整 换句话说 某些元组可能没有data value 然后我在表上建立一个 B 树索引 CREATE INDEX ON b
  • 使用 hibernate 进行动态查询

    我有一个应用程序 我需要使最终用户能够通过某种类型的向导定义选项来创建临时报告 其过程如下 1 User selects the table s he wants to query eg person project activities
  • Google Apps 脚本触发器 - 每当将新文件添加到文件夹时运行

    我想在任何时候执行谷歌应用程序脚本new文件被添加到特定文件夹 目前 我使用的是每 x 分钟运行一次的时钟触发器 但我只需要在向文件夹添加文件时运行脚本 有没有办法做到这一点 与this https stackoverflow com qu
  • 如何通过Object Id和Column Id查询表数据?

    有桌子Clients PK LastName Name Address 1 Vidal Arturo St 2 Lavezzi Ezequiel St 3 Cuadrado Guillermo St 我想得到 通过以下查询 我可以得到前四列

随机推荐