Oracle SQL:在具有不同内容的单个列中计算两次值一次

时间:2018-03-21 01:37:59

标签: oracle

大家好,我有下一张桌子

Name | Gender | Count(Gender)
BBC  |   M    |      31
BBC  |   F    |       1
BBC  |   B    |       3
BBC  |   N    |     160

M: Male
F: Female
B: Both
N: Not Specified

我需要将其分为三类。 M,F,N。

如何制作一个Case语句,当寄存器为B时,男性和女性的计数增加为1。

我需要一张这样的桌子。

Name | Gender | Count(Gender)
BBC  |   M    |      34
BBC  |   F    |       4
BBC  |   N    |     160

我希望我能很好地解释自己。

感谢大家。

5 个答案:

答案 0 :(得分:1)

我会通过使用条件聚合然后取消隐藏来实现:

SELECT * FROM (
    SELECT name, SUM(CASE WHEN gender IN ('M','B') THEN 1 ELSE 0 END) AS "M"
         , SUM(CASE WHEN gender IN ('F','B') THEN 1 ELSE 0 END) AS "F"
         , SUM(CASE WHEN gender = 'N' THEN 1 ELSE 0 END) AS "N"
      FROM my_table
     GROUP BY name
) UNPIVOT ( count_gender FOR gender IN ("M","F","N") );

B值在条件聚合下的M(男性)和F(女性)列下计算 - 然后我们可以将我们的列转换为行。假设您至少使用Oracle 11g - 对于Oracle 10g及更低版本,您将不得不使用Tim Biegeleisen给出的查询。

编辑:如果您有一个计数表(即,如果您的帖子中的表是原始数据而不是聚合的结果),那么替换SUM()以上的计数列代替" 1":

SUM(CASE WHEN gender IN ('M','B') THEN count_gender ELSE 0 END) AS "M"

希望这有帮助。

答案 1 :(得分:1)

这是一种方法。也许不是最简单的代码,但我相信它非常有效。它使用不完整的交叉连接来复制'B'行 - 这样基本数据只读取一次。

with
  inputs ( name, gender, cnt ) as (
    select 'BBC', 'M',  31 from dual union all
    select 'BBC', 'F',   1 from dual union all
    select 'BBC', 'B',   3 from dual union all
    select 'BBC', 'N', 160 from dual union all    
    select 'ZYX', 'M',  55 from dual union all
    select 'ZYX', 'F',  12 from dual union all
    select 'ZYX', 'B',  43 from dual union all
    select 'ZYX', 'N', 123 from dual
)
select   i.name
     ,   case i.gender when 'B' then case h.flag when 1 then 'F' 
                                                 else        'M'
                                     end
                       else          i.gender
         end as gender
     ,   sum(cnt) as cnt
from     inputs i cross join
         ( select 1 as flag from dual union all select 2 from dual ) h
where    h.flag = 1 or i.gender = 'B'
group by i.name
       , case i.gender when 'B' then case h.flag when 1 then 'F' 
                                                 else        'M'
                                     end
                       else          i.gender
         end
order by name, gender
;

输出(来自我在WITH子句中创建的扩展测试数据):

NAME  GENDER  CNT
----  ------  ---
BBC   F         4
BBC   M        34
BBC   N       160
ZYX   F        55
ZYX   M        98
ZYX   N       123

答案 2 :(得分:0)

我没有看到这样做的方法,而没有为两个统计数据生成数据,以涵盖男性和女性。我们可以将一个查询联合起来,这个查询聚合了男性,两者都是一个,而一个是女性和两者。工会的前半部分还包括未指定,因为它需要从某个地方进入。

SELECT
    Name,
    CASE WHEN Gender IN ('M', 'B') THEN 'M' ELSE Gender END AS Gender,
    SUM(cnt) AS cnt
FROM yourTable
WHERE Gender IN ('M', 'B', 'N')
GROUP BY
    Name,
    CASE WHEN Gender IN ('M', 'B') THEN 'M' ELSE Gender END
UNION ALL
SELECT
    Name,
    CASE WHEN Gender IN ('F', 'B') THEN 'F' END AS Gender,
    SUM(cnt) AS cnt
FROM yourTable
WHERE Gender IN ('F', 'B')
GROUP BY
    Name,
    CASE WHEN Gender IN ('F', 'B') THEN 'F' END
ORDER BY
    Name, Gender

enter image description here

Demo

答案 3 :(得分:0)

我认为其他答案过于复杂。我从字面上理解您的原始陈述 - 您有一张按性别分列的表格。如果这个假设不成立,答案会略有改变。只需使用案例陈述在男性和女性中包括B,然后汇总:

WITH yourTable AS (
    SELECT 'BBC' AS Name, 'M' AS Gender, 31 AS cnt from dual UNION ALL
    SELECT 'BBC', 'F', 1  from dual UNION ALL
    SELECT 'BBC', 'B', 3  from dual UNION ALL
    SELECT 'BBC', 'N', 160 from dual
)
SELECT
 SUM(male)
,SUM(female)
,SUM(not_known)
FROM
 (SELECT
   gender
  ,cnt
  ,CASE
    WHEN gender IN ('M','B') THEN cnt
    ELSE 0
   END                          male
  ,CASE
    WHEN gender IN ('F','B') THEN cnt
    ELSE 0
   END                          female
  ,CASE
    WHEN gender = 'N' THEN cnt
    ELSE 0
   END                          not_known
  FROM
   yourTable
 )
;

答案 4 :(得分:-2)

WITH yourTable AS (
    SELECT 'BBC' AS Name, 'M' AS Gender, 31 AS cnt from dual UNION ALL
    SELECT 'BBC', 'F', 1  from dual UNION ALL
    SELECT 'BBC', 'B', 3  from dual UNION ALL
    SELECT 'BBC', 'K', 3  from dual UNION ALL
    SELECT 'BBC', 'N', 160 from dual )select t.*,sum(cnt) over (partition by gender) from yourTable  t where gender in('F','M','N')