【问题标题】:PostgreSQL - Dynamic Tables, insert values from Text array in a functionPostgreSQL - 动态表,在函数中插入文本数组中的值
【发布时间】:2012-02-27 23:21:21
【问题描述】:

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

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

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

对于几个数据类型这不是问题,但对于文本数据类型它是有问题的。

到目前为止的功能如下:

-- 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,甚至用替换替换引号('),直到执行函数(replace(query,l_quote_rep,'''')..我真的不知道现在如何解决这个问题...

提前致谢。

【问题讨论】:

    标签: arrays postgresql dynamic insert plpgsql


    【解决方案1】:

    Arraysaggregatesquote_ident and quote_nullable 是你的朋友。

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

    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$;
    

    【讨论】:

    • 0 是标准的“成功”代码。我错过了一些正确数据类型的转换。这个想法是,并非所有字段都作为文本插入,而是以它的本机数据类型插入。 (现在支持:文本、整数、布尔和双精度)。 (我暂时无法测试它)
    • 作为一项规则,应该存在从文本到任何其他数据类型的强制转换。
    猜你喜欢
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 2016-05-25
    • 1970-01-01
    相关资源
    最近更新 更多