【问题标题】:How to perform the same aggregation on every column, without listing the columns?如何在不列出列的情况下对每一列执行相同的聚合?
【发布时间】:2012-11-25 11:06:21
【问题描述】:

我有一个包含 N 列的表格。我们称它们为c1c2c3c4、...cN。在多行中,我想为 [1, N] 中的每个 X 获取带有 COUNT DISTINCT(cX) 的单行。

c1 | c2 | ... | cn
0  | 4  | ... | 1

有没有一种方法可以在不手动将每个列名写入查询的情况下执行此操作(在存储过程中)?

为什么?

我们遇到了一个问题,即应用程序服务器中的错误意味着我们会用稍后插入的垃圾来重写好的列值。为了解决这个问题,我存储了信息日志结构,其中每一行代表一个逻辑UPDATE 查询。然后,当给出记录完成的信号时,我可以确定是否有任何值被(错误地)覆盖。

多行中单个正确记录的示例:每列最多有一个值。

| id | initialize_time | start_time | end_time |
| 1  | 12:00am         | NULL       | NULL     |
| 1  | 12:00am         | 1:00pm     | NULL     |
| 1  | 12:00am         | NULL       | 2:00pm   |

Reconciled row:
| 1  | 12:00am         | 1:00pm     | 2:00pm   |

我要检测的不可调和记录示例:

| id | initialize_time | start_time | end_time |
| 1  | 12:00am         | NULL       | NULL     |
| 1  | 12:00am         | 1:00pm     | NULL     |
| 1  | 9:00am          | 1:00pm     | 2:00pm   |   -- New initialize time => irreconcilable!

【问题讨论】:

  • 你是问如何获取列名,或者如何进行聚合?
  • 我知道如何获取列名,但我不知道如何在查询中的每个列名周围展开表达式。我想在我的存储过程中避免使用SELECT COUNT DISTINCT(c1), COUNT DISTINCT(c2), ..., COUNT DISTINCT(cN) FROM ...
  • 当然,您可以使用动态 SQL 来执行此操作。顺便问一下,X 有多大?
  • N 的总数约为 30。
  • 就我个人而言,我只需要添加一个审计触发器来记录对表的更改,修复应用程序服务器中的错误,而不必担心这种过于复杂的解决方法。见wiki.postgresql.org/wiki/Audit_trigger_91plus

标签: sql database postgresql relational-database


【解决方案1】:

为此,您需要 动态 SQL,这意味着您必须创建一个函数或运行 DO 命令。由于您不能直接从后者返回值,因此 plpgsql 函数是:

CREATE OR REPLACE function f_count_all(_tbl text
                           , OUT columns text[], OUT counts bigint[])
  RETURNS record LANGUAGE plpgsql AS
$func$
BEGIN

EXECUTE (
    SELECT 'SELECT
     ARRAY[' || string_agg('''' || quote_ident(attname) || '''', ', ') || '], 
     ARRAY[' || string_agg('count(' || quote_ident(attname) || ')', ', ') || ']
    FROM ' || _tbl
    FROM   pg_attribute
    WHERE  attrelid = _tbl::regclass
    AND    attnum  >= 1           -- exclude tableoid & friends (neg. attnum)
    AND    attisdropped is FALSE  -- exclude deleted columns
    GROUP  BY attrelid
    )
INTO columns, counts;

END
$func$;

呼叫:

SELECT * FROM f_count_all('myschema.mytable');

返回:

columns       | counts
--------------+--------
{c1, c2, c3,} | {17 1,0}

this related question 中有关动态 SQL 和 EXECUTE 的更多解释和链接 - 或者更多关于 SO,try this serach 的链接。

与这个问题非常相似:
postgresql - count (no null values) of each column in a table

您甚至可以尝试返回多态记录类型以动态获取单列,但这相当复杂和高级。可能为您的情况付出了太多努力。更多内容请参见this related answer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    相关资源
    最近更新 更多