Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 函数返回给定表名和列名的表_Sql_Postgresql_Plpgsql_Dynamic Sql - Fatal编程技术网

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) 是我在寻找一个函数来做这些事情,我在做什么?