2016-04-12 52 views
1

我有一堆布尔列的表。我想按照每个人的真实值计数这些列。通过值的计数来排列列

我发现了一种使用数列中的真实值的数量:

SELECT count(CASE WHEN col1 THEN 1 ELSE null END) as col1, 
     count(CASE WHEN col2 THEN 1 ELSE null END) as col2 
     .... 
FROM my_table; 

但这种方法有两个问题:

  1. 我必须手动输入列的名称
  2. 我必须再由价值

转的结果,为了有AW唉做整个操作一个查询?

+0

可能'crosstab'会处理它。请提供http://sqlfiddle.com样本数据和期望的结果集 – lad2025

+0

@ lad2025与'crosstab',您还必须手动输入列的名称。除非你使用动态声明,这与OP提供的方式基本相同(就结果而言) –

+1

编辑你的问题并提供你想要的结果 –

回答

0

如果我理解正确的话,你可以用一个巨大的union all做到这一点:

select c.* 
from ((select 'col1' as which, sum(case when col1 then 1 else 0 end) as cnt from t 
    ) union all 
     (select 'col2' as which, sum(case when col2 then 1 else 0 end) as cnt from t 
    ) union all 
     . . . 
    ) c 
order by cnt desc; 

虽然你仍然需要输入的结果,这也回避了换位。

1

这实际上并不是一个交叉表作业(或其他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 
    

    这是简单的部分。你的另外一个要求是很难:

    1. 我必须手动输入列

    此功能需要你的表名,并从系统目录检索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 
    

    Works为任何表排名所有boolean列的值为true。有更多的解释

    相关答案:

    为了了解函数参数,请阅读此

    +0

    'LATERAL和VALUES' :)我总是想知道为什么人们想要模拟SELECT *行为 – lad2025