Sql 如何保存通过触发器的字符中带有逗号的数据?
我有一个字符类型可变的字段,但在尝试保存包含小数的数据时出错。我想毫无问题地保存这些数据 这是我的触发器:Sql 如何保存通过触发器的字符中带有逗号的数据?,sql,postgresql,plpgsql,database-trigger,Sql,Postgresql,Plpgsql,Database Trigger,我有一个字符类型可变的字段,但在尝试保存包含小数的数据时出错。我想毫无问题地保存这些数据 这是我的触发器: CREATE TRIGGER "public.usuarios_trigger_process_audit" BEFORE INSERT OR UPDATE OR DELETE ON usuarios FOR EACH ROW EXECUTE PROCEDURE process_audit(); 本程序如下: DECLARE newtable text;
CREATE TRIGGER "public.usuarios_trigger_process_audit"
BEFORE INSERT OR UPDATE OR DELETE
ON usuarios
FOR EACH ROW
EXECUTE PROCEDURE process_audit();
本程序如下:
DECLARE
newtable text;
col information_schema.columns %ROWTYPE;
txtquery text;
line_old TEXT;
tmpquery text;
i int;
columns_old text[];
BEGIN
IF ( TG_TABLE_SCHEMA = 'public' ) THEN
SELECT TG_TABLE_NAME || '_actividad' INTO newtable; /* select TG_RELNAME || '_actividad' into newtable; */
ELSE
SELECT TG_TABLE_SCHEMA || '_' || TG_TABLE_NAME || '_actividad' INTO newtable; /* select TG_RELNAME || '_actividad' into newtable; */
END IF;
PERFORM creartablaactividad( TG_TABLE_SCHEMA, TG_TABLE_NAME );
IF ( TG_OP = 'DELETE' ) THEN
line_old := TRIM( substr(OLD::text,2,(select length(OLD::text)-2)) );
columns_old := STRING_TO_ARRAY( line_old, ',' );
i := 0;
tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
tmpquery := replace(tmpquery,','''',',',NULL,');
/* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''D'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''D'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
EXECUTE txtquery;
RETURN OLD;
ELSIF ( TG_OP = 'UPDATE' ) THEN
line_old := TRIM( substr(OLD::text,2,(select length(OLD::text)-2)) );
columns_old := STRING_TO_ARRAY( line_old, ',' );
i := 0;
tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
tmpquery := replace(tmpquery,','''',',',NULL,');
tmpquery := replace(tmpquery,','''',',',NULL,');
/* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''ANT'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''ANT'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
EXECUTE txtquery;
line_old := TRIM( substr(NEW::text,2,(select length(NEW::text)-2)) );
columns_old := STRING_TO_ARRAY( line_old, ',' );
i := 0;
tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
tmpquery := replace(tmpquery,','''',',',NULL,');
/* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''U'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''U'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
EXECUTE txtquery;
RETURN NEW;
ELSIF ( TG_OP = 'INSERT' ) THEN
line_old := TRIM( substr(NEW::text,2,(select length(NEW::text)-2)) );
columns_old := STRING_TO_ARRAY( line_old, ',' );
i := 0;
tmpquery := '''' || array_to_string(columns_old, ''',''') || '''';
tmpquery := replace(tmpquery,','''',',',NULL,');
/* SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, inet_client_addr(), now (), ''I'',' || replace(tmpquery, ',''''',',NULL') into txtquery; */
SELECT 'INSERT INTO actividad.' || newtable ||' SELECT user, now (), ''I'',' || replace(tmpquery, ',''''',',NULL') into txtquery;
EXECUTE txtquery;
RETURN NEW;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
我的桌子通常是: 错误: 您可以使用
format()
创建动态SQL查询,因为它将自动正确处理标识符和文本。人们通常忽略的一点是,您可以使用(…).*
将单个记录表达式扩展到其所有列-这也适用于新的和旧的记录触发器中的变量,例如选择(新)。*
您还可以使用execute
语句的关键字将变量传递给动态SQL。不需要在记录和文本表示之间来回转换记录
利用这种可能性,您的触发功能可以简化为:
DECLARE
l_sql text;
BEGIN
IF TG_TABLE_SCHEMA = 'public' THEN
newtable := TG_TABLE_NAME || '_actividad';
ELSE
newtable := TG_TABLE_SCHEMA || '_' || TG_TABLE_NAME || '_actividad';
END IF;
PERFORM creartablaactividad(TG_TABLE_SCHEMA, TG_TABLE_NAME);
l_sql := 'INSERT INTO actividad.%I SELECT current_user, current_timestamp, %L, ($1).*';
IF TG_OP = 'DELETE' THEN
execute format(l_sql, newtable, 'D') using OLD;
RETURN OLD;
ELSE
-- covers UPDATE and INSERT
execute format(l_sql, newtable, 'U') using NEW;
RETURN NEW;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
使用像%I
和%L
这样的占位符也可以只定义一次实际的SQL并重新使用它。这些“参数”被format()
函数替换(该函数保留$1
)
注意在SQL字符串中使用了($1)。*
。这将使execute
语句将记录参数$1
扩展到其所有列。使用
关键字通过以“本机”方式传递记录本身
在没有目标列列表的情况下使用INSERT
(INSERT into some_table…
而不是INSERT into some_table(col1,col2,…)
)是一件非常脆弱的事情。如果源和目标不匹配,则插入很容易失败
如果您不在审计表上运行大规模报告(在这种情况下,使用显式列名会更有效),您可能需要考虑使用JSON
或HSTORE
列来存储整个记录的更通用的审计触发器。有几个现成的审核触发器可用:
您需要展示一些示例。例如,您的代码是什么样子的?字符串中使用逗号没有问题。当您保存一条记录时,该记录通过触发器保存副本。这里有个问题。大家好,欢迎来到堆栈溢出。您能告诉我们您正在运行的确切SQL、任何触发器以及您得到的确切错误吗?然后我们可以更好地回答您的问题。我已经更新了这个问题。错误看起来很清楚-您可以尝试smth,比如插入到t(c1,c2)中选择c1,c2,c3,c4,c5
返回列的数量大于目标列的数量