Teradata划分错误?

Teradata划分错误?,teradata,rank,percentile,dense-rank,Teradata,Rank,Percentile,Dense Rank,我有一个同事不想在百分位排名中包含空行。默认的Teradata函数似乎只是将null视为集合中的最小值,因此我决定手动进行计算。我开始使用下面的查询来测试我的等式 drop table tmp; create multiset volatile table tmp ( num byteint ) primary index (num) on commit preserve rows ; insert into tmp values (1) ;insert into tmp value

我有一个同事不想在百分位排名中包含空行。默认的Teradata函数似乎只是将null视为集合中的最小值,因此我决定手动进行计算。我开始使用下面的查询来测试我的等式

drop table tmp;

create multiset volatile table tmp (
  num byteint
) primary index (num)
  on commit preserve rows
;

insert into tmp
values (1)
;insert into tmp
values (2)
;insert into tmp
values (1)
;insert into tmp
values (4)
;insert into tmp
values (null)
;insert into tmp
values (4)
;insert into tmp
values (null)
;insert into tmp
values (2)
;insert into tmp
values (9)
;insert into tmp
values (null)
;insert into tmp
values (10)
;insert into tmp
values (10)
;insert into tmp
values (11)
;

select
  num,
  case
    when num is null then 0
    else cast(dense_rank() over (partition by case when num is not null then 1 else 2 end order by num) as number)
  end as str_rnk,
  q.nn,
  str_rnk/q.nn as pct_rnk
from tmp
cross join (
    select cast(count(num) as number) as nn from tmp
) q
order by num
;
因此,我希望在结果集中看到以下内容:

num   str_rnk  nn  pct_rnk
null        0  10        0
null        0  10        0
null        0  10        0
   1        1  10      0.1
   1        1  10      0.1
   2        2  10      0.2
   2        2  10      0.2
   4        3  10      0.3
   4        3  10      0.3
   9        4  10      0.4
  10        5  10      0.5
  10        5  10      0.5
但是我得到了一个结果,看起来它做了一个常规的
排名
,而不是一个
密集的排名
,如下所示:

num   str_rnk  nn  pct_rnk
null        0  10        0
null        0  10        0
null        0  10        0
   1        1  10      0.1
   1        1  10      0.1
   2        2  10      0.3
   2        2  10      0.3
   4        3  10      0.5
   4        3  10      0.5
   9        4  10      0.7
  10        5  10      0.8
  10        5  10      0.8

我知道我可以在子查询中设置排名,它会按照我期望的方式进行计算,但为什么它不按照我现在的方式进行呢?

这并不能回答您的问题。这不是分区的问题,这似乎是一些奇怪的问题运行的演员和密集_排名两次在同一选择

考虑:

select
  num,
  case
    when num is null then 0
    else cast(dense_rank() over (partition by case when num is not null then 1 else 2 end order by num) as number)
  end as str_rnk,

  case
    when num is null then 0
    else cast(dense_rank() over (partition by case when num is not null then 1 else 2 end order by num) as number)
  end as str_rnk2
from tmp
cross join (
    select cast(count(num) as number) as nn from tmp
) q;


+--------+---------+----------+
|  num   | str_rnk | str_rnk2 |
+--------+---------+----------+
| 1      |       1 |        1 |
| 1      |       1 |        1 |
| 2      |       2 |        3 |
| 2      |       2 |        3 |
| 4      |       3 |        5 |
| 4      |       3 |        5 |
| 9      |       4 |        7 |
| 10     |       5 |        8 |
| 10     |       5 |        8 |
| 11     |       6 |       10 |
| <null> |       0 |        0 |
| <null> |       0 |        0 |
| <null> |       0 |        0 |
+--------+---------+----------+

但这并不能回答你的问题。这不是分区的问题,这似乎是一些奇怪的问题运行的演员和密集_排名两次在同一选择

考虑:

select
  num,
  case
    when num is null then 0
    else cast(dense_rank() over (partition by case when num is not null then 1 else 2 end order by num) as number)
  end as str_rnk,

  case
    when num is null then 0
    else cast(dense_rank() over (partition by case when num is not null then 1 else 2 end order by num) as number)
  end as str_rnk2
from tmp
cross join (
    select cast(count(num) as number) as nn from tmp
) q;


+--------+---------+----------+
|  num   | str_rnk | str_rnk2 |
+--------+---------+----------+
| 1      |       1 |        1 |
| 1      |       1 |        1 |
| 2      |       2 |        3 |
| 2      |       2 |        3 |
| 4      |       3 |        5 |
| 4      |       3 |        5 |
| 9      |       4 |        7 |
| 10     |       5 |        8 |
| 10     |       5 |        8 |
| 11     |       6 |       10 |
| <null> |       0 |        0 |
| <null> |       0 |        0 |
| <null> |       0 |        0 |
+--------+---------+----------+

正如JNevill指出的,这是一个bug,您应该使用Teradata支持打开一个事件:

SELECT
   num,
   -- cast to FLOAT or DECIMAL works as expected
   Cast(Dense_Rank() Over (ORDER BY num) AS NUMBER) AS a,
   a AS b
FROM tmp

 num    a    b
----  ---  ---
   ?    1    1
   ?    1    1
   ?    1    1
   1    2    4
   1    2    4
   2    3    6
   2    3    6
   4    4    8
   4    4    8
   9    5   10
  10    6   11
  10    6   11
  11    7   13
但是添加
QUALIFY ab
会返回一个空结果:-)

等级百分比的原始计算基于

Cast(Rank() Over (ORDER BY num) -1 AS DEC(18,6)) / Count(*) Over ()
如果要排除空值,可以切换到
Count(num)
NULLs LAST

SELECT
   num,
   CASE
      WHEN num IS NOT NULL 
      THEN Cast(Dense_Rank() Over (ORDER BY num NULLS LAST) AS DECIMAL(18,6)) 
      ELSE 0
   END AS str_rnk,
   str_rnk / Count(num) Over ()
FROM tmp
或者使用那种圆滑的
num*0
技巧:

SELECT
   num,
   Coalesce(Dense_Rank()
            Over (ORDER BY num NULLS LAST) 
             * (num * 0 +1.000000), 0) AS str_rnk,
   str_rnk / Count(num) Over ()
FROM tmp

正如JNevill指出的,这是一个bug,您应该使用Teradata支持打开一个事件:

SELECT
   num,
   -- cast to FLOAT or DECIMAL works as expected
   Cast(Dense_Rank() Over (ORDER BY num) AS NUMBER) AS a,
   a AS b
FROM tmp

 num    a    b
----  ---  ---
   ?    1    1
   ?    1    1
   ?    1    1
   1    2    4
   1    2    4
   2    3    6
   2    3    6
   4    4    8
   4    4    8
   9    5   10
  10    6   11
  10    6   11
  11    7   13
但是添加
QUALIFY ab
会返回一个空结果:-)

等级百分比的原始计算基于

Cast(Rank() Over (ORDER BY num) -1 AS DEC(18,6)) / Count(*) Over ()
如果要排除空值,可以切换到
Count(num)
NULLs LAST

SELECT
   num,
   CASE
      WHEN num IS NOT NULL 
      THEN Cast(Dense_Rank() Over (ORDER BY num NULLS LAST) AS DECIMAL(18,6)) 
      ELSE 0
   END AS str_rnk,
   str_rnk / Count(num) Over ()
FROM tmp
或者使用那种圆滑的
num*0
技巧:

SELECT
   num,
   Coalesce(Dense_Rank()
            Over (ORDER BY num NULLS LAST) 
             * (num * 0 +1.000000), 0) AS str_rnk,
   str_rnk / Count(num) Over ()
FROM tmp

很好地抓住了双重演员这一点,去掉其中一个演员就可以完成任务,但也有一些TD的妙语在起作用<代码>计数(*)
包括空值,这不是我想要的。
str\u rnk
nn
必须是某种十进制接受类型,或者结果都是
pct\u rnk
中的0。我听过
数字
计算最准确吗?
*(num*0+1)
返回空值,我需要0来显示,但我可以使用
zeroifnull
函数。最后,我将ocont放在子查询中,以确保它只运行一次。我确信DBMS已经针对类似的内容进行了优化,但我想确定。
num*0
为分组返回0或NULL。比案件陈述书快
*(num*0+1)
乘以结果时间1,除非它为null,否则它将使整个结果为null,从而消除了对外壳语句的需要。运行最后一个,我想你会看到你需要什么
1.0
强制计算取小数点后一位,因此不需要强制转换。我肯定会在内部大小写中使用乘法,但是
*(num*0+1.0)
返回空值,我需要它在最后为0。我可以使用
zeroifnull
函数,但我假设这只是一个case语句的包装器。是的,您完全可以将整个内容包装在
zeroifnull()
中,或者返回更长的case语句。我认为CPU使用率将是两者之间的一个平局。
num*0
技巧很巧妙:-)但我认为不会有太大的CPU差异…很好地抓住了双重演员的问题,去掉其中一个就可以完成任务,但也有一些TD妙语在起作用<代码>计数(*)
包括空值,这不是我想要的。
str\u rnk
nn
必须是某种十进制接受类型,或者结果都是
pct\u rnk
中的0。我听过
数字
计算最准确吗?
*(num*0+1)
返回空值,我需要0来显示,但我可以使用
zeroifnull
函数。最后,我将ocont放在子查询中,以确保它只运行一次。我确信DBMS已经针对类似的内容进行了优化,但我想确定。
num*0
为分组返回0或NULL。比案件陈述书快
*(num*0+1)
乘以结果时间1,除非它为null,否则它将使整个结果为null,从而消除了对外壳语句的需要。运行最后一个,我想你会看到你需要什么
1.0
强制计算取小数点后一位,因此不需要强制转换。我肯定会在内部大小写中使用乘法,但是
*(num*0+1.0)
返回空值,我需要它在最后为0。我可以使用
zeroifnull
函数,但我假设这只是一个case语句的包装器。是的,您完全可以将整个内容包装在
zeroifnull()
中,或者返回更长的case语句。我认为CPU使用率将是两者之间的一个平局。
num*0
技巧很巧妙:-)但我不认为会有很大的CPU差异…听到你认为这是一个bug,我感到很欣慰。我试着想清楚“为什么”它可能会这样做,但找不到任何好的理由。听到你认为这是一个bug,我感到很欣慰。我试图想清楚“为什么”它可能会这样做,但找不出任何好的理由。