我在 PostgreSQL 12 中有一个触发函数,它执行如下操作:
CREATE OR REPLACE FUNCTION "my_latlon_function"()
RETURNS trigger AS
$$
BEGIN
latcolumn:= (
SELECT column_name
FROM information_schema.columns
WHERE table_schema = TG_TABLE_SCHEMA
AND table_name = TG_TABLE_NAME
AND column_name ~* '.*lat.*'
);
loncolumn := (
SELECT column_name
FROM information_schema.columns
WHERE table_schema = TG_TABLE_SCHEMA
AND table_name = TG_TABLE_NAME
AND column_name ~* '.*lon.*'
);
EXECUTE 'select $1.' || loncolumn USING NEW INTO lon;
EXECUTE 'select $1.' || latcolumn USING NEW INTO lat;
-- do much stuff
RETURN NEW;
END
$$
LANGUAGE 'plpgsql';
问题是,lat
andlon
列的名称中有大写字母,例如myLatitude
and myLongitude
。触发器函数能够检索这些名称,这没问题。
问题出在两个EXECUTE
语句中,其中列名似乎变成了小写,如该错误所述(在触发触发器时的基础 QUERY 中):
ERROR: column "mylongitude" not found in data type gpspoints
LINE 1: select $1.myLongitude
^
QUERY: select $1.myLongitude
CONTEXT: PL/pgSQL function my_latlon_function() line 24 at EXECUTE
********** Error **********
ERROR: column "mylongitude" not found in data type gpspoints
SQL state: 42703
Context: PL/pgSQL function my_latlon_function() line 24 at EXECUTE
我知道 PostgreSQL 确实需要将名称中包含大写字母的列名括在双引号中。因此,我尝试在两个 EXECUTE 语句中设置双引号,例如:
EXECUTE 'select $1.' || "loncolumn" USING NEW INTO lon;
EXECUTE 'select $1.' || "latcolumn" USING NEW INTO lat;
但是错误保持不变。
如果可能,如何在 PostgreSQL 触发器函数中处理 CamelCase 列名?
如果不是,为什么?
format
与%I
标识符的占位符一起使用:在需要时使用
format()
(如 Laurenz 演示)或quote_ident()
. 看:此外,您的触发功能可以像这样更有效:
db<>在这里摆弄
(这是假设列名总是明确匹配!?)
演示
quote_ident()
。列名已经正确引用,我们可以concat()
稍后进行。目录表
pg_catalog.pg_attribute
明显比information_schema.columns
. 比较这两个命令的输出以了解原因:看:
在这种特殊情况下,我们也可以方便地使用and
TG_RELID
来代替。TG_TABLE_SCHEMA
TG_TABLE_NAME
此外,在 PL/pgSQL 中,单独的分配相对昂贵。尽量减少他们的人数。
虽然性能差异仍然很小,但每个插入的行都会调用一次此触发器函数。加起来大插入...
撇开,
col ~* 'lon'
完全等价于col ~* '.*lon.*'
。