我正在尝试创建一个函数,该函数将采用通用表并将N列转换为大写。我没有找到解决这类问题的方法,但我能够提出以下建议:
create or replace function uc_on_insert()
returns trigger as
$$
declare
p_tbl varchar = TG_TABLE_NAME;
p_sch varchar = TG_TABLE_SCHEMA;
i varchar;
begin
for i in
(select column_name
from INFORMATION_SCHEMA.COLUMNS
where 1=1
and table_name ilike p_tbl
and table_schema ilike p_sch
and data_type ='character varying')
loop
execute 'new.' || i || ' = upper(new.' || i || ');';
return new;
end loop;
end;
$$ language plpgsql;
我目前收到此错误:
ERROR: syntax error at or near "new"
LINE 1: new.c1 = upper(new.c1);
^
QUERY: new.c1 = upper(new.c1);
预期的输入是,在任何表格上我都有这个触发器:
insert into table_one('a', 'b');
>> A, B
如果我把这个触发器放在另一张桌子上:
insert into table_two ('a', 3);
>> A, 3
等。
答案 0 :(得分:3)
这是一个非常棘手的问题。
您的尝试一定会失败,因为当前行变量NEW
在EXECUTE
内不可见。即使它是,NEW
是行类型(记录),而不是数组。与数组元素不同,行的字段不能通过数字索引引用。这会导致SQL中的各种问题,因为(与数组相对)每个字段可以具有不同的数据类型,并且SQL期望知道预先处理的数据类型。确实非常棘手。
幸运的是,我们之前处理过类似的问题:
你会在那里找到充分的解释 适用于触发器功能,并根据列的数据类型,它可能如下所示:
CREATE OR REPLACE FUNCTION trg_uc_on_insert()
RETURNS trigger AS
$func$
BEGIN
EXECUTE 'SELECT ' || array_to_string(ARRAY(
SELECT CASE WHEN atttypid = 'varchar'::regtype
-- atttypid = ANY('{text, bpchar, varchar}'::regtype[])
THEN 'upper(($1).' || quote_ident(attname)
|| ')::' || atttypid::regtype::text
ELSE '($1).' || quote_ident(attname)
END AS fld
FROM pg_catalog.pg_attribute
WHERE attrelid = pg_typeof(NEW)::text::regclass
AND attnum > 0
AND attisdropped = FALSE
ORDER BY attnum
), ',')
USING NEW
INTO NEW;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
如果您想将相同的规则应用于其他基本字符类型,请使用注释的替代方法。
CREATE TRIGGER trg_t_insbef
BEFORE INSERT
ON t -- works for any table
FOR EACH ROW
EXECUTE PROCEDURE trg_uc_on_insert();
只要您只在表中使用简单类型并想要大写所有字符数据,就会有另一种原始的,快速而简单的方法:将整行转换为{{1大写文本表示形式,强制转换为行类型并使用结果更新text
。有关表的行类型的详细信息
触发功能
NEW
我们必须分解行类型,因为CREATE OR REPLACE FUNCTION trg_uc_simple_on_insert()
RETURNS trigger AS
$func$
BEGIN
EXECUTE 'SELECT ($1::' || pg_typeof(NEW) || ').*'
USING upper(NEW::text)
INTO NEW;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
逐个分配目标行类型的各个字段。我们不能一次分配整行。仔细观察,“通用”解决方案也是如此,不太明显。
虽然字符数据在文本表示中区分大小写,但其他基本数字或日期/时间数据类型则不区分大小写。因此简单的方法可靠地工作。也可能与大多数其他类型一样。但是我没有和别人一起测试,当然也有例外。您必须验证您使用的数据类型。
此外,虽然代码比使用泛型方法更短更简单,但这并不一定更快,尤其是对于许多未受影响的列。不过,在简单的情况下,它可能要快得多。