【问题标题】:Values with IN Operator used in CASE statement should count onceCASE 语句中使用 IN 运算符的值应计算一次
【发布时间】:2018-08-24 09:50:17
【问题描述】:

我希望这有助于解释比标题更多的内容。基本上我有一个疑问:

SELECT 
  e.USER
, e.CODE
, CASE WHEN 
  e.CODE IN ('a.01', 'b.04', 'c.20', x.01)
  THEN 1
  ELSE NULL
  END AS case
FROM TABLE e

这会吸引我:

USER   CODE     case
01     a.01     1
01     a.02     NULL
01     a.04     NULL
01     b.04     1
01     c.20     1
02     a.11     NULL
02     b.04     1
03     b.05     NULL
04     c.20     1

但是,我需要的有点复杂。我需要将代码分组,以便为​​每个用户的每个组提供一个值 USER

例如:

, CASE WHEN 
  e.CODE IN ('a.01', 'b.04') --Group A
  OR
  e.CODE IN ('c.20', x.01)   --Group B
  THEN 1
  ELSE NULL
  END AS case

上面的代码是错误的,因为我需要的是如果 GROUP A 或 GROUP B 中的至少一个代码存在于用户中,那么只给出一个值 1 ELSE NULL

会产生的东西:

USER   CODE     case
01     a.01     1    --Group A
01     a.02     NULL
01     a.04     NULL
01     b.04     NULL --GROUP A, now NULL because we just need to count once per group 
01     c.20     1    --GROUP B
02     a.11     NULL
02     b.04     1   
03     b.05     NULL
04     c.20     1

如果这有帮助,我最终想计算每个用户的案例以产生以下结果:

USER     count
01       2       --Not 3
02       1
03       1
04       1

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    我确信有一种更聪明的方法,但如果我理解正确,这可能会奏效:

    SELECT sub.user,
           sub.code,
           CASE WHEN ROW_NUMBER() OVER
                     ( PARTITION BY GroupCode
                           ORDER BY inGroup DESC
                     ) = 1 
                 AND MAX(inGroup) OVER
                     ( PARTITION BY GroupCode
                     ) = 1 THEN 1 
                ELSE 0
            END FieldYourAskingFor       
      FROM (SELECT e.*,
                   CASE WHEN e.CODE IN ('a.01', 'b.04', 'c.20', x.01) THEN 1 
                    END AS inGroup,
                   CASE WHEN e.CODE IN ('a.01', 'b.04') THEN 'GroupA'
                        WHEN e.CODE IN ('c.20', x.01) THEN 'GroupB'
                    END AS GroupCode
              FROM TABLE e
           ) sub
    

    【讨论】:

      【解决方案2】:

      我会使用 row_number()case 表达式:

      select USER, CODE, 
             (case when row_number() over (partition by USER, grp order by CODE) = 1 and
                        grp is not null 
                   then 1
              end) as case
      from ( select *, (case when CODE IN ('a.01', 'b.04') then 'GA' 
                             when CODE IN ('c.20', 'x.01') then 'GB' 
                        end) as grp
             from table
          ) t;
      

      【讨论】:

        【解决方案3】:

        我会这样做。

        -- create test table and data
        declare @tbl table(usr char(2), code char(4))
        insert into @tbl values ('01', 'a.01'), ('01', 'b.04')
        insert into @tbl values ('01', 'c.20'), ('02', 'b.04'), ('04', 'c.20')
        
        -- actual query
        select
           usr,
           sign(sum(iif(code in ('a.01', 'b.04'), 1, 0))) +          -- 1 if group a, else 0  
           sign(sum(iif(code in ('c.20', 'x.01'), 1, 0))) as count   -- 1 if group b, else 0
        from @tbl
        group by usr
        

        输出是:

        usr count
        --- -----
        01      2
        02      1
        04      1
        

        【讨论】:

          【解决方案4】:

          您可以使用ROW_NUMBER() 为每个用户设置一次值:

          SELECT e.USER, e.CODE,
                 (CASE WHEN ROW_NUMBER() OVER (PARTITION BY flag, e.USER ORDER BY e.code) = 1
                       THEN flag
                  END) as flag
          FROM (SELECT e.*,
                       (CASE WHEN e.CODE IN ('a.01', 'b.04', 'c.20', x.01) THEN 1 END) as flag
                FROM TABLE e
               ) e;
          

          编辑:

          对于评论中修改后的问题:

          SELECT e.USER, e.CODE,
                 (CASE WHEN ROW_NUMBER() OVER (PARTITION BY flag, e.USER ORDER BY e.code) = 1
                       THEN SIGN(flag)
                  END) as flag
          FROM (SELECT e.*,
                       (CASE WHEN e.CODE IN ('a.01', 'b.04') THEN 1
                             WHEN e.CODE IN ('c.20', x.01) THEN 2
                        END) as flag
                FROM TABLE e
               ) e;
          

          【讨论】:

          • 谢谢。我的错,我应该在问题中澄清(我现在会做)。我需要将它们分成 2 个组,因为一个用户可能会出现在 GROUP A 和 GROUP B 中的情况。在这种情况下,每个用户都应该有 1
          【解决方案5】:

          感谢您的反馈。我正在发布一个有效的答案,但我不确定它是否是最佳答案:

          SELECT
             t.USER
            ,t.CODE
            ,COUNT DISTINCT(t.case)
          
          FROM (
          
          SELECT 
            e.USER
          , e.CODE
          , CASE 
            WHEN e.CODE IN ('a.01', 'b.04') --Group A
            THEN 'grpA'
            WHEN e.CODE IN ('c.20', x.01)   --Group B
            THEN 'grpB'
            ELSE NULL
            END AS case
          
          FROM TABLE e
          ) t
          
          GROUP BY t.USER
          

          我意识到这会让我得到按用户分组的结果,但最后我只是想按用户计算案例。不确定是否有人可以使用它以获得更好的格式。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-06-22
            • 1970-01-01
            • 2021-11-21
            • 1970-01-01
            • 1970-01-01
            • 2016-09-01
            • 1970-01-01
            相关资源
            最近更新 更多