1

我声明了以下标志:

0 - None
1 - Read
2 - Write
4 - View

我想编写一个查询,该查询将对该位掩码进行分组并获取使用的每个标志的计数。

person  mask
  a      0
  b      3
  c      7
  d      6

结果应该是:

flag        count
 none        1
 read        2
 write       3
 view        2

任何提示将不胜感激。

对于克雷格

SELECT  lea.mask as trackerStatusMask,
        count(*) as count
FROM    Live le 
INNER JOIN (
 ... --some guff
) lea on le.xId = lea.xId
WHERE   le.xId = p_xId   
GROUP BY lea.mask;
4

2 回答 2

3

SQL小提琴

select
    count(mask = 0 or null) as "None",
    count(mask & 1 > 0 or null) as "Read",
    count(mask & 2 > 0 or null) as "Write",
    count(mask & 4 > 0 or null) as "View"
from t
于 2013-08-01T01:34:47.523 回答
2

最简单的旋转结果

这是我的处理方法:

 -- (after fixing the idiotic mistakes in the first version)
 SELECT
    count(nullif(mask <> 0, True)) AS "none",
    count(nullif(mask & 2,0))      AS "write",
    count(nullif(mask & 1,0))      AS "read",
    count(nullif(mask & 4,0))      AS "view"
FROM my_table;

-- ... though @ClodAldo's version of it below is considerably clearer, per comments.

这并没有这样做GROUP BY;相反,它会扫描表并一次性收集数据,从而生成面向列的结果。

如果您需要以行的形式使用它,您可以使用模块中的crosstab函数tablefunc或手动旋转结果。

如果你真的必须GROUP BY,请分解位掩码

您不能GROUP BY以简单的方式使用它,因为它希望行恰好属于一个组。您的行出现在多个组中。如果您必须使用GROUP BY,则必须通过生成“爆炸”位掩码来执行此操作,其中一个输入行被复制以产生多个输出行。这可以通过LATERAL9.3 中的函数调用或 9.2 中的 SRF-in-SELECT 来完成,或者只需对VALUES子句进行连接:

SELECT
   CASE 
     WHEN mask_bit = 1 THEN 'read'
     WHEN mask_bit = 2 THEN 'write'
     WHEN mask_bit = 4 THEN 'view'
     WHEN mask_bit IS NULL THEN 'none'
   END AS "flag",
   count(person) AS "count"
FROM t
LEFT OUTER JOIN (
    VALUES (4),(2),(1)
) mask_bits(mask_bit)
ON (mask & mask_bit = mask_bit)
GROUP BY mask_bit;

不过,我不认为你会很幸运地让它像单表扫描一样高效。

于 2013-08-01T01:34:59.470 回答