【问题标题】:Case statement with Ranking function具有排名功能的案例陈述
【发布时间】:2017-08-22 22:16:08
【问题描述】:

您好,在排名方面寻求帮助。

我正在使用 SQL 处理 Teradata,我正在尝试按特定组然后按年龄对列表进行排名。

例如:我想按组排名,然后只对所选组下 21 岁以下的人进行排名。

但是,当我使用下面的查询时,它似乎没有考虑到组中的成员,并且只有当他们满足 case 语句中的条件时才分配。

select
policy, 
age, 
case when age <'21' then  '1'else '0' end as Under21,
case when age <'21' then dense_rank () over (order by group, age desc)  else '0' end as Rank_Under_21
from   Table

【问题讨论】:

    标签: sql teradata ranking ranking-functions


    【解决方案1】:

    您可以使用partition by 子句:

    dense_rank () over (partition by policy, case when age < 21 then 1 end
                        order by group, age desc)
    

    注意:如果age 是一个数字字段(应该是),那么不要将它与字符串进行比较:省略引号。如果age 是字符串类型,请注意与另一个字符串的比较将按字母顺序进行,因此 '9' > '21'。

    【讨论】:

    • 谢谢@Trincot,这非常有用并帮助回答了我的问题!
    【解决方案2】:

    您的代码仍然对所有年龄进行排名,CASE 只是将高年龄排名替换为零。

    另一种解决方案(除了@trincot's answer)将CASE移到RANK中:

    CASE
      WHEN age < 21 
        THEN Rank ()
             Over (PARTITION BY policy
                   ORDER BY CASE WHEN age < 21 THEN age END DESC)
      ELSE 0
    END
    

    这也对所有年龄进行了排名,但排名靠前的会排在最后,因此获得了高排名,它被外部 CASE 替换为 0。

    【讨论】:

    • 感谢您的帮助,这似乎最适合我的需要。欣赏它。
    • 这对我有用,但我必须将新列命名为别名。
    【解决方案3】:

    以下代码适用于 MS SQL Server。感谢@Victor Hugo Terceros,提供示例代码。

    DECLARE @tbl TABLE
      (
         age INT,
         grp VARCHAR(20)
      )
    
    INSERT INTO @tbl
    SELECT 1,
           'A'
    UNION
    SELECT 12,
           'A'
    UNION
    SELECT 20,
           'A'
    UNION
    SELECT 19,
           'B'
    UNION
    SELECT 30,
           'B'
    UNION
    SELECT 11,
           'B'
    UNION
    SELECT 4,
           'C'
    UNION
    SELECT 14,
           'C'
    UNION
    SELECT 5,
           'B'
    UNION
    SELECT 16,
           'D'
    
    SELECT grp     AS Policy,
           age,
           under21 AS Under21,
           CASE
             WHEN under21 = 0 THEN Dense_rank()
                                     OVER(
                                       partition BY grp
                                       ORDER BY under21age DESC)
             ELSE 0
           END     AS Rank_Under_21
    FROM   (SELECT CASE
                     WHEN age < 21 THEN 0
                     ELSE 1
                   END AS Under21,
                   CASE
                     WHEN age < 21 THEN age
                     ELSE 0
                   END AS under21age,
                   age,
                   grp
            FROM   @tbl) AS t  
    

    【讨论】:

    • 谢谢@Victor。我有一张桌子,里面有不同的组,与该组相关的年龄。我正在尝试按组对年龄小于 21 的行进行排名。例如: A 组 - 63 排名:0 A 组 - 54 排名:0 A 组 - 19 排名:1 A 组 - 18 排名:2 组B - 65 等级:0 B 组 - 50 等级:0 B 组 - 19 等级:0 B 组 - 8 等级:1 我尝试了你的建议,它有效,只是它似乎只在符合案例陈述标准并且似乎是为所选组列出的行号。
    • 您能否编辑您的问题并提供所需的结果集。
    【解决方案4】:

    我的建议是按组列分区,然后按年龄排名

    ---------------Test Table with data---------
    declare @tbl table(age int, policy varchar(20))
    insert into @tbl
    select 1, 'A' union
    select 12, 'A' union
    select 20, 'A' union
    select 19, 'B' union
    select 30, 'B' union
    select 11, 'B' union
    select 4, 'C' union 
    select 14, 'C' union
    select 5, 'B' union
    select 16, 'D'
    ---------------Main Query--------------------
    select policy,age, 
    '1' as Under21, 
    rank() over (partition by policy order by age desc) as Rank_Under_21 
    from @tbl
    where age <21
    union
    select policy,age, 
    '0' as Under21, 
     0 as Rank_Under_21 
    from @tbl
    where age >=21
    order by policy asc,age desc
    

    【讨论】:

    • 谢谢维克多。我要做的是按组计算有多少成员年龄小于 21 岁。如果他们确实有年龄低于 21 岁的行,请对他们进行排名。
    • 我更新了我的查询,它得到了您期望的确切结果,正如您在图片中看到的那样
    猜你喜欢
    • 1970-01-01
    • 2016-12-16
    • 1970-01-01
    • 2023-04-10
    • 2010-10-30
    • 2016-05-13
    • 2016-02-21
    • 1970-01-01
    • 2017-10-19
    相关资源
    最近更新 更多