Sql 函数返回给定表名和列名的表
假设我在两个不同的数据库中有一个名为Sql 函数返回给定表名和列名的表,sql,postgresql,plpgsql,dynamic-sql,Sql,Postgresql,Plpgsql,Dynamic Sql,假设我在两个不同的数据库中有一个名为static的表houses和partments 静态表包含房屋的静态信息,如房屋大小,无房间,泳池,水疗 数据库中的静态表包含以下列: pool spa house_size sauna no_rooms 1 1 25 1 2 1 0 35 1 3 pool spa house_size sauna 1 1 25
static
的表houses
和partments
静态
表包含房屋的静态信息,如房屋大小
,无房间
,泳池
,水疗
数据库中的静态表
包含以下列:
pool spa house_size sauna no_rooms
1 1 25 1 2
1 0 35 1 3
pool spa house_size sauna
1 1 25 1
1 0 35 1
static
数据库中的表具有如下列:
pool spa house_size sauna no_rooms
1 1 25 1 2
1 0 35 1 3
pool spa house_size sauna
1 1 25 1
1 0 35 1
我想运行下面的查询而不引发任何错误。目前,我收到错误消息,因为公寓.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;
它可以工作,但是当涉及更多的列时,这个查询会变得混乱
我要找的是:
创建一个函数,该函数接受列名和表名,然后执行我在上面的查询中执行的连接,并返回一个表。(应为泛型,适用于参数中给定的列名和表名,并返回一个表。)
还有其他好的解决办法吗
不要胡闹这些问题。将视图添加到两个包含所有列的数据库中。在第一个数据库中:
create view v_static as
select pool, spa house_size, sauna, no_rooms
from status;
在第二部分:
create view v_static as
select pool, spa house_size, sauna, null as no_rooms
from status;
然后使用视图而不是基表。SQL是一种严格类型化的语言,Postgres函数必须声明其返回类型。从函数返回可变数量的列仅在解决方法(如多态类型)下才可能。见:
但在您的案例中,我们无法处理行类型,因为每个数据库的行类型都不同。剩余选项:返回匿名记录,并为每次调用提供列定义列表。我通常不建议这样做,因为在每次调用中提供列定义列表可能会很乏味,而且往往毫无意义。但是你的可能是一个罕见的有意义的用例
但是,您必须知道可能缺少的列的数据类型。在本演示中,我将假定integer
。否则,您必须另外传递数据类型,并相应地构建查询
CREATE OR REPLACE FUNCTION f_dynamic_select(_tbl regclass
, _cols VARIADIC text[]) -- ①
RETURNS SETOF record -- ② anonymous records
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE -- ③ dynamic SQL
format(
'SELECT %s FROM %s' -- ④ safe against SQLi
, (
SELECT string_agg(COALESCE(quote_ident(a.attname)
, '0 AS ' || quote_ident(t.col) -- assuming integer!
), ', ' ORDER BY t.ord) -- ⑤
FROM unnest(_cols) WITH ORDINALITY t(col, ord) -- ⑤
LEFT JOIN pg_attribute a ON a.attrelid = _tbl -- ⑥
AND a.attnum > 0
AND NOT a.attisdropped
AND a.attname = t.col
)
, _tbl
);
END
$func$;
打电话(重要!)
您的示例调用,使用基于以下列的表达式:
SELECT pool, case when spa = 1 then 1 else 0 end as has_spa -- ⑦ expressions
, sauna, house_size
, case when no_rooms > 2 then 1 else 0 end as rooms
FROM f_dynamic_select('static', 'pool', 'spa', 'sauna', 'house_size', 'no_rooms')
AS t(pool int, spa int, house_size int, sauna int, no_rooms int);
小提琴
① 该函数的表名为regclass
type。见:
。。。后跟任意列名称列表-按有意义的顺序排列<代码>可变的
应该对此很方便。见:
请注意,我们将列名作为区分大小写的单引号字符串传递。非(双引号)标识符
② 这可能是我第一次建议从函数返回匿名记录——在[plpgsql]标记上回答了近1000个问题之后
如果函数定义为返回记录
数据类型,
然后必须出现别名或关键字AS
,后跟一列
定义列表的格式为(列名称数据类型[,…])
。这个
列定义列表必须与列的实际数量和类型匹配
函数返回的列
③
④ 防止SQL注入,因为表名作为regclass
传递,并且SELECT
列表使用quote_ident()
仔细连接。见:
⑤ 使用带有顺序性的
保留列的原始顺序。见:
⑥ <代码>左键连接到系统目录以标识现有列。见:
⑦ 将传递列上的表达式移动到外部选择
免责声明:如果有必要,我只会介绍这种复杂程度。也许您可以在每个数据库中使用简单的视图?只需将no\u rooms
添加到没有数据的表中即可修复数据。或者在两个数据库中创建一个具有相同名称的视图,在其中添加值。您知道如何编写一个函数,接受列名作为参数并返回一个表吗?@AwaishKumar。对于你在这个问题上提出的问题,这似乎不是一个合理的解决方案。如果你想做这样的事情,你可以问一个新问题。我在最后两件事中补充了,我想从这个问题中得到什么?1) 是我在寻找一个函数来做这些事情,我在做什么?