【问题标题】:Count on case Oracle依靠案例甲骨文
【发布时间】:2016-12-29 09:37:21
【问题描述】:

我们在 oracle 数据库中有以下数据 -

col1 col2 
Z1     A
Z1     B
Z2     A
Z2     C
Z3     A   
Z4     D

我想以这样的方式计算第二列 -

输出 -

col2  count
A      3     (Z1,Z2,Z3)
B      0     (Dont count if A is already present for record)
C      0
D      1      (Z4)

最好的问候

【问题讨论】:

    标签: sql oracle oracle11g


    【解决方案1】:

    您可以使用窗口函数rank() 来实现。

    select col2, count(case when rn = 1 then 1 end) cnt from (
    select t.*,
        rank() over (partition by col1 order by case when col2 = 'A' then 1 else 2 end) rn
    from table t
    ) group by col2;
    

    【讨论】:

    • 我不会工作,因为我想优先考虑 A(如果存在)
    • @AnirudhD 你能试一试吗?
    • @AnirudhD 它给出了您期望的确切答案。
    • 这个想法很棒,但是将 Z4/C 添加到数据中,您就会看到缺陷。将您的 row_number 子句替换为 rank() over (partition by col1 order by case when col2 = 'A' then 1 else 2 end) as rn 以解决它。
    • @Thorsten OMG。你是对的。更新。感谢您的建议。
    【解决方案2】:

    您的命题的最通用解决方案,其中每个键 COL1 仅在键 COL2 的第一次出现中计算(按字母顺序)

    WITH tab AS
    (
        SELECT 'Z1' col1, 'A' col2 FROM dual UNION ALL
        SELECT 'Z1' col1, 'B' col2 FROM dual UNION ALL
        SELECT 'Z2' col1, 'A' col2 FROM dual UNION ALL
        SELECT 'Z2' col1, 'C' col2 FROM dual UNION ALL
        SELECT 'Z3' col1, 'A' col2 FROM dual UNION ALL
        SELECT 'Z4' col1, 'D' col2 FROM dual 
    ), tab2 as (
    select COL1, COL2,
    row_number() over (partition by COL1 order by COL2) as rn
    from tab)
    select COL1, COL2,
    case when rn = 1 then 1 else 0 end is_valid
    from tab2
    order by 1,2
    ;
    
    COL1 COL2   IS_VALID
    ---- ---- ----------
    Z1   A             1 
    Z1   B             0 
    Z2   A             1 
    Z2   C             0 
    Z3   A             1 
    Z4   D             1 
    

    剩下的就是简单的分组,在 IS_VALID 上有一个 SUM

    select COL2, sum(is_valid) cnt  from tab3 -- TAB3 is the above row source
    group by COL2
    order by 1
    
    COL2        CNT
    ---- ----------
    A             3 
    B             0 
    C             0 
    D             1 
    

    【讨论】:

      【解决方案3】:

      谢谢各位。但我可以这样做 -

      select  count(case
                  when (LISTAGG(col2,'-') WITHIN GROUP (ORDER BY col2)) like '%A%' then 1
                  else null
              end) A,
              count(case
                  when (LISTAGG(col2,'-') WITHIN GROUP (ORDER BY col2)) = 'B' then 1
                  else null
              end) B,
              count(case
                  when (LISTAGG(col2,'-') WITHIN GROUP (ORDER BY col2)) = 'C' then 1
                  else null
              end)  C,
               count(case
                  when (LISTAGG(col2,'-') WITHIN GROUP (ORDER BY col2)) = 'D' then 1
                  else null
              end) D
      from T
      GROUP BY col1
      

      感谢您的回复

      【讨论】:

        【解决方案4】:

        假设你的表名是table_name,一种方法是使用这个:

        WITH table_a AS 
        (
            SELECT DISTINCT col1
            FROM table_name
            WHERE col2 = 'A'
        )
        SELECT col2,
            SUM(CASE WHEN col1 IN (SELECT col1 FROM table_a) 
                THEN DECODE(col2, 'A', 1, 0) 
                ELSE 1 END
            ) count
        FROM table_name
        GROUP BY col2
        ORDER BY col2;
        

        测试正常:

        WITH table_name AS
        (
            SELECT 'Z1' col1, 'A' col2 FROM dual UNION ALL
            SELECT 'Z1' col1, 'B' col2 FROM dual UNION ALL
            SELECT 'Z2' col1, 'A' col2 FROM dual UNION ALL
            SELECT 'Z2' col1, 'C' col2 FROM dual UNION ALL
            SELECT 'Z3' col1, 'A' col2 FROM dual UNION ALL
            --SELECT 'Z4' col1, 'B' col2 FROM dual UNION ALL
            SELECT 'Z4' col1, 'D' col2 FROM dual 
        )
        , table_a AS 
        (
            SELECT DISTINCT col1
            FROM table_name
            WHERE col2 = 'A'
        )
        SELECT col2,
            SUM(CASE WHEN col1 IN (SELECT col1 FROM table_a) 
                THEN DECODE(col2, 'A', 1, 0) 
                ELSE 1 END
            ) count
        FROM table_name
        GROUP BY col2
        ORDER BY col2;
        

        【讨论】:

          【解决方案5】:

          您想要计算 col2 为“A”或 col1 不存在“A”记录的每条记录。

          select 
            col2, 
            count(
              case 
                when col2 = 'A' or col1 not in (select col1 from table_name where col2 = 'A') then 1 
              end) as cnt
          from table_name
          group by col2;
          

          【讨论】:

            【解决方案6】:
            select   col2, count(case when col2 = col3 then 'x' end) as ct
            from     ( select col2, min(col2) over (partition by col1) as col3
                       from   your_table
                     )
            group by col2
            order by col2   --  if needed
            ;
            

            解释

            有一个内部查询(也称为“子查询”),它为原始表中的每一行返回一行。它按原样返回col2,并返回一个附加(新)列,标记为col3col3 计算为 col2 的“第一个”或 min() 值(按字母顺序),用于原始表中与 col1 具有相同值的所有行与当前行相同。这是解析函数的典型示例; partition by col1group by col1 类似,但它返回组中的所有行(原始表中的所有原始行),而不是像聚合函数一样每组一行。

            要查看内部查询本身的作用,请选择它并在您最喜欢的前端运行它。您可以将col1 添加到内部查询的选择中 - 这将使该查询中发生的事情更加清晰。您将获得初始表,其中还有一列col3,它显示col1 的每个值的“最小值”col2。我没有在子查询中包含col1,因为我不需要它,但是将其添加回来以查看子查询的实际作用。

            然后在外部查询中,我从内部查询中获取结果,并按col2 分组。对于每个col2,我计算它等于col2 对应col1 值的“最小”值的次数。这就是case 表达式在count() 函数中的作用;当col2 不等于col3 时,case 返回null(默认情况下),因此不计算表达式(因此行)。

            我应该补充一点,以这种方式编写的查询假定原始表中没有重复的(col1, col2) 行。如果有,则内部子查询应从子子查询中选择;我的代码的第 3 行应该是

            from (select distinct col1, col2 from your_table)
            

            【讨论】:

            • 您能否在您的答案周围添加更多上下文。仅代码或仅链接的答案很难理解。如果您可以在帖子中添加更多信息,这将对提问者和未来的读者都有帮助。
            【解决方案7】:

            使用以下脚本:

             SELECT A.COL2, NVL(B.CNT, 0) AS CNT
                  FROM (SELECT DISTINCT COL2 FROM TET) A
                  LEFT JOIN (SELECT COL2, COUNT(COL2) AS CNT
                               FROM (SELECT SUBSTR(F, 1, INSTR(F, ',') - 1) AS COL2,
                                            ROW_NUMBER() OVER(PARTITION BY SUBSTR(F, 1, INSTR(F, ',') - 1) ORDER BY SUBSTR(F, 1, INSTR(F, ',') - 1)) AS U
                                       FROM (SELECT COL1,
                                                    LISTAGG(COL2, ',') WITHIN GROUP(ORDER BY COL2) || ',' AS F
                                               FROM TET
                                              GROUP BY COL1)) A
                              GROUP BY COL2) B
                    ON A.COL2 = B.COL2
                 ORDER BY A.COL2;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-10-05
              • 2011-07-19
              • 2014-09-11
              • 2011-06-15
              相关资源
              最近更新 更多