这实际上不是交叉表作业(或其他 RDBMS 中的“枢轴”),而是反向操作,如果您愿意的话,是一个反交叉表。一种优雅的技术是在LATERAL 连接中使用VALUES 表达式。
基本查询可能如下所示,它负责:
- 然后我必须转置结果并按值排序
SELECT c.col, c.ct
FROM (
SELECT count(col1 OR NULL) AS col1
, count(col2 OR NULL) AS col2
-- etc.
FROM tbl
) t
, LATERAL (
VALUES ('col1', col1)
, ('col2', col2)
-- etc.
) c(col, ct)
ORDER BY 2
这是最简单的部分。您的其他要求更难:
- 我必须手动输入列的名称
此函数获取您的表名并从系统目录pg_attribute 中检索元数据。它是上述查询的动态实现,可以防止 SQL 注入:
CREATE OR REPLACE FUNCTION f_true_ct(_tbl regclass)
RETURNS TABLE (col text, ct bigint) AS
$func$
BEGIN
RETURN QUERY EXECUTE (
SELECT format('
SELECT c.col, c.ct
FROM (SELECT %s FROM tbl) t
, LATERAL (VALUES %s) c(col, ct)
ORDER BY 2 DESC'
, string_agg (format('count(%1$I OR NULL) AS %1$I', attname), ', ')
, string_agg (format('(%1$L, %1$I)', attname), ', ')
)
FROM pg_attribute
WHERE attrelid = _tbl -- valid, visible, legal table name
AND attnum >= 1 -- exclude tableoid & friends
AND NOT attisdropped -- exclude dropped columns
AND atttypid = 'bool'::regtype -- only character types
);
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT * FROM f_true_ct('tbl'); -- table name optionally schema-qualified
结果:
col | ct
------+---
col1 | 3
col3 | 2
col2 | 1
适用于任何表,以按true 值的计数对所有boolean 列进行排名。
要了解函数参数,请阅读以下内容:
更多解释的相关答案: