2

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

这个想法是能够生成有关表内容的“元数据”以用于分析目的。这只能通过对每一列运行查询来完成(AFAIK),以便找出,比如说......最小/最大/计数值等。为了使过程自动化,最好让数据库生成查询,然后执行。

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

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

优点是无论列数如何,数据库都会生成代码。现在我想到了无数个地方来存储这些查询,可以是某种变量,也可以是表列,然后让这些查询执行。我想将生成的查询存储在一个变量中,然后使用EXECUTE(or ) 语句执行它们,这是这里EXECUTE IMMEDIATE使用的方法(见右窗格),但 Postgres 不会让我在函数之外声明一个变量,我一直在抓挠我的头脑与这将如何结合在一起,无论这是否是要遵循的方向,也许还有更简单的东西。

你有什么指示吗,我目前正在尝试这样的事情,受到其他问题的启发,但不知道我是否朝着正确的方向前进:

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;    
4

2 回答 2

6

系统统计

在您自己动手之前,请查看系统表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()每列都允许聚合函数。但是你需要知道如何使用 PL/pgSQL。

CREATE OR REPLACE FUNCTION f_min_of(_tbl anyelement)
  RETURNS SETOF anyelement
  LANGUAGE plpgsql 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$;

致电(重要!):

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

db<>fiddle here
sqlfiddle

您需要了解这些概念:

  • plpgsql 中的动态 SQLEXECUTE
  • 多态类型
  • Postgres 中的行类型和表类型
  • 如何防御 SQL 注入
  • 聚合函数
  • 系统目录

相关答案及详细解释:

类型不匹配的特殊困难

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

但是,与基础列相比,某些聚合函数返回相关但不同的数据类型。例如,min(varchar_column)returnstext是位兼容的,但不是完全相同的数据类型。PL/pgSQL 函数在这里有一个弱点,它坚持要求完全RETURNS按照子句中声明的数据类型。没有尝试转换,甚至没有隐式转换,更不用说赋值转换了。

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

这就是这个构造作为解决方法出现的地方:

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

通过将整行显式转换为基础表的行类型,我们强制赋值转换以获取每一列的原始数据类型。

This might fail for some aggregate function. sum() returns numeric for a sum(bigint_column) to accommodate for a sum overflowing the base data type. Casting back to bigint might fail ...

于 2015-04-14T00:58:13.973 回答
0

@Erwin Brandstetter, Many thanks for the extensive answer. pg_stats does indeed provide a few things, but what I really need to draw a complete profile is a variety of things, min, max values, counts, count of nulls, mean etc... so a bunch of queries have to be ran for each columns, some with GROUP BY and such.

Also, thanks for highlighting the importance of data types, i was sort of expecting this to throw a spanner in the works at some point, my main concern was with how to automate the query generation, and its execution, this last bit being my main concern.

I have tried the function you provide (I probably will need to start learning some plpgsql) but get a error at the SELECT (t::tbl) :

ERROR: type "tbl" does not exist

btw, what is the (t::abc) notation referred as, in python this would be a list slice, but it’s probably not the case in PLPGSQL

于 2015-04-14T08:20:33.153 回答