我有一个带有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!

最佳答案

为此,您需要动态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的更多说明和链接-或更多关于try this serach的信息。

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

您甚至可以尝试返回多态记录类型以动态获取单列,但这是相当复杂和高级的。您的案件可能需要太多的精力。更多关于this related answer

关于sql - 如何在每个列上执行相同的汇总而不列出列?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13760230/

10-16 13:13