arrays - PostgreSQL - 动态表,在函数中插入文本数组中的值

标签 arrays postgresql dynamic insert plpgsql

客户想要将任何东西存储在单独的表中。 (长话短说,这是必要的)。 为此,我构建了一个 Postgres 函数来在它自己的命名空间中动态创建新表。

这些表可以有 2、4 或 100 列,这正是用户想要的。 没问题,这行得通。这些动态表中使用的数据类型是原生的,例如文本、 bool 值、整数等。

现在问题来了,我必须向这些表中插入数据。关键是,用户不能直接访问表,他们将通过一个函数来实现。

对于一些数据类型这不是问题,但对于文本数据类型这是有问题的。

这是到目前为止的功能:

-- Function: add(integer, text[])

-- DROP FUNCTION add(integer, text[]);

CREATE OR REPLACE FUNCTION add(id integer, fields text[])
  RETURNS integer AS
$BODY$
DECLARE
l_line_ending text := ')';
  l_fieldtype integer;
  l_ito_table_name text;
  l_ito_fieldnames text;
  l_field ito_fields%rowtype;
  l_first_loop boolean := true;
  l_values_to_insert text := 'VALUES (';
  l_loop_counter integer := 0;
  l_query text;

BEGIN
  select into l_ito_table_name ito_table_name from ito where id = target_ito_id;
  l_ito_fieldnames := 'insert into ' || l_ito_table_name || '(';
    FOR l_field IN SELECT * FROM ito_fields
    WHERE ito_fields.ito_id = target_ito_id
    order by ito_fields.id asc
    LOOP
        l_loop_counter := l_loop_counter +1;
        l_fieldtype := l_field.fieldtype;
        if not l_first_loop THEN
            l_values_to_insert := (l_values_to_insert || ', ');
        end if;
        if l_field.fieldtype = 1 THEN
             l_values_to_insert := (l_values_to_insert || '''' || (fields[l_loop_counter]) || '''' );
        elsif l_field.fieldtype = 2 THEN
            l_values_to_insert := quote_literal(l_values_to_insert || private.cast_to_integer(fields[l_loop_counter]));
        elsif l_field.fieldtype = 3 THEN
            l_values_to_insert := quote_literal(l_values_to_insert || private.cast_to_boolean(fields[l_loop_counter]));
        elsif l_field.fieldtype = 4 THEN
            l_values_to_insert := quote_literal(l_values_to_insert || private.cast_to_float(fields[l_loop_counter]));
        else 
            return 103;
        end if;
        if l_first_loop then
            l_ito_fieldnames := l_ito_fieldnames || l_field.column_name;
            l_first_loop := false;
        else
            l_ito_fieldnames := l_ito_fieldnames || ', ' || l_field.column_name;
        end if;
    END LOOP;
    l_ito_fieldnames := l_ito_fieldnames || l_line_ending;
    l_values_to_insert := ((l_values_to_insert) || (l_line_ending));
    l_query := (l_ito_fieldnames || l_values_to_insert);
    EXECUTE l_query;
  return 0;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION add(integer, text[])
  OWNER TO postgres;

表ito_fields存储了所有的字段元数据,所以数据类型、版本、描述都存储在这里。 ito 表存储所有动态表数据。

这个函数的重点是引号。插入函数是动态创建的,因此我必须在插入函数的文本字段周围添加一些引号。 我一这样做,Postgres 就会出错。即使使用 quote_literal 函数,它仍然是一个问题,因为字符串连接(我知道,安全风险,但现在这不是问题)。

我试过使用quote_literal, quote_ident, 甚至用replacement替换引号('),直到execute function (replace(query, l_quote_rep, '''')..我真的一点头绪都没有现在如何解决这个问题...

提前致谢。

最佳答案

Arrays , aggregates , quote_ident and quote_nullable是你的 friend 。

这应该可行,而且代码更短:

CREATE OR REPLACE FUNCTION add(id integer, fields text[])
  RETURNS integer AS
$BODY$
DECLARE
  l_ito_table_name text;
  l_query text;
  l_fields text;
  r_values text;
BEGIN
    --get table name
    SELECT INTO l_ito_table_name quote_ident(ito_table_name) FROM ito WHERE id = target_ito_id;
    -- get column names
    SELECT INTO l_fields
    array_to_string( array_agg(quote_ident(column_name)), ',' )
    FROM ito_fields
    WHERE ito_fields.ito_id = target_ito_id
    order by ito_fields.id asc;
    -- prepare values
    SELECT INTO r_values
    array_to_string( array_agg(quote_nullable(u.name)), ',' )
    FROM unnest(fields) u(name);
    l_query := 'insert into ' || l_ito_table_name || '(' || l_fields || ') values (' || r_values || ')';
    EXECUTE l_query;
    return 0; -- why 0?
END;
$BODY$;

关于arrays - PostgreSQL - 动态表,在函数中插入文本数组中的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9160877/

相关文章:

hibernate - 通过 Hibernate 的 PostgreSql 数据库备份作为 Web 应用程序中的持久层

postgresql - 无法从 postgres 获取结果

arrays - 将列表解码为集合

c++ - 重载新的和删除运算符

javascript - 使用 ng-click 为每次点击添加 HTML 代码

css - 如何动态更改 UI 中的字体大小以在 JavaFX 中始终保持相同的宽度?

c - 疯狂是免费的()

php - 如何在 PHP 中将一行存储到数组中并回显数组的某个值?

postgresql - 如何改变postgresql中的分区

javascript - 在 Javascript 中是否可以创建具有动态(未确定)属性/成员的对象?