客户想要将任何东西存储在单独的表中。 (长话短说,这是必要的)。 为此,我构建了一个 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/