假设我有一个名为 static
在两个不同的数据库中 houses
以及 apartments
. static
表包含房屋的静态信息,例如 house_size
, no_rooms
, pool
, spa
. static
中的表 houses
数据库有如下列:
pool spa house_size sauna no_rooms
1 1 25 1 2
1 0 35 1 3
``` `static` 中的表 `apartments` 数据库有如下列:
pool spa house_size sauna
1 1 25 1
1 0 35 1
我想运行下面的查询而不引起任何错误。目前,我得到的错误是 `no_rooms` 中不存在列 `apartments.public.static` .
select pool, case when spa = 1 then 1 else 0 end as has_spa,
sauna, house_size, case when no_rooms > 2 then 1 else 0 end as rooms
from static;
我尝试过的解决方案:
WITH static_new AS (SELECT s.*
FROM (SELECT 0 AS no_rooms) AS dummy
LEFT JOIN LATERAL
( SELECT
pool, spa, sauna, house_size, no_rooms
FROM static
) AS s on true)
SELECT * FROM static_new;
它可以工作,但是当涉及到更多的列时,这个查询会变得混乱。
我要找的是:
创建一个接受列名和表名的函数,然后执行我在上面的查询中执行的连接并返回一个表(应为泛型,适用于参数中给定的列名和表名,并返回表。)
还有什么好办法吗?
2条答案
按热度按时间flvtvl501#
sql是一种严格类型化的语言,postgres函数必须声明其返回类型。从函数中返回可变数量的列只能通过变通方法(如多态类型)实现。请参见:
pl/pgsql中如何按行类型返回表
但是我们不能在您的案例中使用行类型,因为不同的数据库的行类型不同。剩下的选项:返回匿名记录并为每个调用提供列定义列表。我通常不建议这样做,因为为每个调用提供一个列定义列表可能会很乏味,而且往往毫无意义。但你的可能是其中一个罕见的用例,它是有意义的。
不过,您必须知道可能缺少的列的数据类型。我假设
integer
在本演示中。否则,必须另外传递数据类型并相应地构建查询。呼叫(重要!)
您的示例调用,包含基于以下列的表达式:
db<>在这里摆弄
① 函数采用表名作为
regclass
类型。请参见:表名作为postgresql函数参数
... 后跟任意列名称列表-按有意义的顺序排列。
VARIADIC
这样应该很方便。请参见:在单个参数中传递多个值
请注意,我们将列名作为区分大小写的单引号字符串传递。非(双引号)标识符。
② 这可能是我第一次建议从函数返回匿名记录—在[plpgsql]标记上有近1000个答案之后。手册:
如果函数已定义为返回
record
数据类型,然后是别名或关键字AS
必须存在,后跟表单中的列定义列表( column_name data_type [, ... ])
. 列定义列表必须与函数返回的实际列数和类型匹配。③ 动态sql手册。
④ 对sql注入是安全的,因为表名作为
regclass
,和SELECT
列表是使用quote_ident()
小心。请参见:在plpgsql函数中将表名和列名定义为参数?
⑤ 使用
WITH ORDINALITY
保持列的原始顺序。请参见:带有元素编号的postgresql unnest()
⑥
LEFT JOIN
到系统目录pg_attribute
以标识现有列。请参见:在postgresql中选择具有特定列名的列
⑦ 将在传递的列上生成的表达式移到外部
SELECT
.免责声明:如果必须的话,我只会介绍这种复杂程度。也许你可以在每个数据库中使用简单的视图?
u91tlkcl2#
别把问题搞砸了。向两个数据库中添加一个包含所有列的视图。在第一个数据库中:
在第二种情况下:
然后使用视图而不是基表。