我有一个包含 N 列的表。我们称他们为c1
,c2
,c3
,c4
,... 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!
答案 0 :(得分:3)
您需要动态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。