在PL / pgSQL中动态执行查询

时间:2015-04-13 22:27:59

标签: postgresql aggregate-functions plpgsql dynamic-sql dynamic-queries

我已经找到了解决方案(我认为)我将要求在Oracle和SQL Server上提出的问题,但似乎无法将其转化为Postgres解决方案。我正在使用Postgres 9.3.6。

我们的想法是能够生成元数据"关于用于分析目的的表格内容。这只能通过为每列运行查询来完成(AFAIK),以便找出,例如...... min / max / count值等。为了使过程自动化,最好让DB生成查询,然后执行。

使用示例salesdata表,我能够为每列生成选择查询,并使用以下代码段返回min()值:

SELECT 'SELECT min('||column_name||') as minval_'||column_name||' from salesdata '  
FROM information_schema.columns 
WHERE table_name = 'salesdata'

优点是db将生成代码而不管列数。 现在我想到了无数的地方存储这些查询,无论是某种变量还是表格列,我们的想法是让这些查询执行。 我想过将生成的查询存储在变量中,然后使用EXECUTE(或EXECUTE IMMEDIATE)语句执行它们,这是使用here的方法(参见右侧窗格),但Postgres赢了&#39 ;让我在一个函数之外声明一个变量,我一直在试着如何将它组合在一起,无论这个方向是否遵循,或许还有更简单的东西。

您是否有任何指示,我目前正在尝试这样的事情,受到other question的启发,但不知道我是否朝着正确的方向前进:

CREATE OR REPLACE FUNCTION foo()
RETURNS void AS
$$
DECLARE
    dyn_sql text; 
BEGIN            
dyn_sql := SELECT 'SELECT min('||column_name||') from salesdata'    
    FROM information_schema.columns 
    WHERE table_name = 'salesdata';
execute dyn_sql
END
$$ LANGUAGE PLPGSQL;    

2 个答案:

答案 0 :(得分:4)

系统统计

在您自己推出之前,请查看系统表pg_statistic或视图pg_stats

  

此视图仅允许访问对应的pg_statistic行   用户有权阅读的表格,因此是安全的   允许对此视图进行公共读取访问。

它可能已经有一些您要计算的统计数据。它由ANALYZE填充,因此您可以在检查之前为新(或任何)表运行它。

-- ANALYZE tbl;  -- optionally, to init / refresh
SELECT * FROM pg_stats
WHERE tablename = 'tbl'
AND   schemaname = 'public';

通用动态plpgsql函数

似乎您想要返回给定表中每列的最小值。这不是一项简单的任务,因为函数(如一般的SQL)要求在创建时知道返回类型 - 或者至少在调用时借助多态数据类型

此功能可自动安全地完成所有操作。适用于任何表,只要每列允许聚合函数min()。但是你需要知道你对plpgsql的看法。

CREATE OR REPLACE FUNCTION f_min_of(_tbl anyelement)
  RETURNS SETOF anyelement AS
$func$
BEGIN
RETURN QUERY EXECUTE (
   SELECT format('SELECT (t::%2$s).* FROM (SELECT min(%1$s) FROM %2$s) t'
                , string_agg(quote_ident(attname), '), min(' ORDER BY attnum)
                , pg_typeof(_tbl)::text)
   FROM   pg_attribute
   WHERE  attrelid = pg_typeof(_tbl)::text::regclass
   AND    NOT attisdropped  -- no dropped (dead) columns
   AND    attnum > 0        -- no system columns
   );
END
$func$  LANGUAGE plpgsql;

呼叫:

SELECT * FROM f_min_of(NULL::tbl);  -- tbl being the table name

SQL Fiddle.

您需要了解这些概念:

  • 带有EXECUTE的plpgsql中的动态SQL。
  • 多态类型。
  • Postgres中的行类型和表类型。
  • 如何抵御SQL注入。
  • 汇总功能。
  • 系统目录。

相关答案详细解释:

类型不匹配的特殊困难

我正在利用为每个现有表定义行类型的Postgres。使用多态类型的概念,我能够创建适用于任何表的一个函数。

但是,与基础列相比,某些聚合函数返回相关但不同的数据类型。例如,min(varchar_column)返回text,它与位兼容,但不是完全相同的数据类型。 plpgsql函数在这里有一个弱点,并坚持在RETURNS子句中声明的数据类型完全。没有尝试施放,甚至不是隐式演员,也不是说任务演员。

应该改进。用Postgres 9.3测试。没有用9.4重新测试,但我很确定,这方面没有任何改变。

这就是这个结构的用武之地:

SELECT (t::tbl).* FROM (SELECT ... FROM tbl) t;

起初似乎扭曲了。这是解决方法:通过将整行强制转换为基础表的行类型,我们强制赋值转换为每列提供原始数据类型。

请注意,某些聚合函数可能会失败。 sum()numeric返回sum(bigint_column)以容纳溢出基本数据类型的总和。回到bigint可能会失败......

答案 1 :(得分:0)

@Erwin Brandstetter,非常感谢广泛的答复。 pg_stats确实提供了一些东西,但我真正需要绘制一个完整的配置文件是各种各样的事情,最小值,最大值,计数,空值计数,平均值等...所以必须运行一堆查询每列,一些有GROUP BY等。

另外,由于强调了数据类型的重要性,我有点期待在某些时候抛出一个扳手,我主要担心的是如何自动生成查询及其执行,最后一点是我的主要关注点。

我已经尝试过你提供的功能(我可能需要开始学习一些plpgsql)但是在SELECT(t :: tbl)处出错:

ERROR: type "tbl" does not exist
顺便问一下,在python中这是什么(t :: abc)表示法,这将是一个列表切片,但在PLPGSQL中可能不是这样的