如何在 postgres 中创建表并插入具有动态值的数据

Posted

技术标签:

【中文标题】如何在 postgres 中创建表并插入具有动态值的数据【英文标题】:How to create a table and insert data with dynamic values in postgres 【发布时间】:2020-02-06 10:34:22 【问题描述】:

我正在尝试编写一个表名动态出现的存储过程。 还要检查表是否已经存在,如果不存在就创建。

然后我尝试将数据插入到下表中,如下所示。 在这里,我将pkeyfiledata 作为参数传递以插入查询,其中pkey 是一个字符串,filedata 是一个json 数据,看起来像 "customer": "John Doe", "items": "product": "Beer","qty": 6

我已经尝试了下面的查询,但是表没有被创建它正在给出消息

注意:标识符 public.tablename_11111 将被截断为 public.tablename_11111

这里的表名是public.tablename_11111

    CREATE OR REPLACE FUNCTION public.generate_table(tb_name text)
    RETURNS text LANGUAGE 'plpgsql'
    COST 100 VOLATILE AS $BODY$

    BEGIN
        EXECUTE format('
            CREATE TABLE IF NOT EXISTS %I(
               id serial PRIMARY KEY,
               pkey VARCHAR (250)  NULL,
               fpo_data TEXT NULL
            )', tb_name || '_pk');


            EXECUTE 'INSERT INTO' || tb_name || '_pk (pkey, fpo_data) VALUES
        ('|| pkey ||', '|| filedata ||')';

        END;
    $BODY$;

【问题讨论】:

【参考方案1】:

首先:%I,当与 public.tablename_11111 这样的名称一起使用时,不会做你想做的事。

您最终会得到一个名为 "public.tablename_11111" 的表,而不是架构 public 中的表 tablename_11111。为此,您应该将架构和表名分开,并使用格式%I.%I:

EXECUTE
   format(
      'CREATE TABLE %I.%I (...)',
      schema_name, tb_name || '_pk'
   );

其次,您的 INSERT 语句容易受到 SQL 注入的攻击。您还必须在那里使用format 函数,就像在CREATE TABLE 中一样。

【讨论】:

我尝试将 %I 替换为 %I。%我收到以下错误错误:format() 的参数太少 对,我说你应该分开模式和表名。我应该说:使模式和表成为两个不同的函数参数,并将两者都提供给format。格式字符串中的每个% 模式都必须有一个对应的参数。 你能输入吗?我没有完全理解你想说的话 谢谢。我尝试了您的代码,存储过程现在运行良好,但是当我尝试从 public.tablename_11111 运行 select * 时,我收到类似关系“public.tablename_11111”不存在的错误 不,那不可能。您真正运行的必须是select * from "public.tablename_11111";。请注意使 PostgreSQL 将其视为单个标识符而不是模式限定表的双引号。也许您正在使用某些工具错误地为您添加这些引号。【参考方案2】:

理想情况下,您应该将架构名称和表名称作为两个单独的值传递。最好不要将值连接到 SQL 字符串中,而是使用占位符。主要是这样您就不必担心正确格式化它们。

类似于以下内容:

CREATE OR REPLACE FUNCTION public.generate_table(tb_schema text, tb_name text, ???)
RETURNS text 
  LANGUAGE plpgsql --<< the language name is an identifier, don't quote it
  COST 100 VOLATILE 
AS $BODY$
BEGIN
  tb_name := tb_name ||'_pk';

  EXECUTE format('
        CREATE TABLE IF NOT EXISTS %I.%I (
           id serial PRIMARY KEY,
           pkey VARCHAR (250)  NULL,
           fpo_data TEXT NULL
        )', tb_schema, tb_name);

  -- where do pkey and filedata come from? 
  EXECUTE format('INSERT INTO %I.%I (pkey, fpo_data) VALUES (:1, :2)', 
                 tb_schema, tb_name)
      using pkey, filedata;  

END;
$BODY$;

【讨论】:

以上是关于如何在 postgres 中创建表并插入具有动态值的数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Postgres 中创建表时将空列设置为带时区的时间戳

在 clickhouse 中创建表时如何将自定义默认值添加到 Nullable 类型?

postgres:从命令行在数据库中创建表

在Oracle 11g 中创建表时如何保存表?

通过终端在 InfluxDB 中创建表

在配置单元中创建表时向列添加默认值