NTILE 仅适用于非零值

NTILE only for values different from zero

我有一列有很多零,我只想将非零值放入 N 组(大约)大小相等。所有零值都应获得组号 0。是否有一种优雅的方法可以做到这一点?

我的第一个方法是使用下面代码中的 ntile_v2,但是这样 bin 编号就不会以 1 开头,我也不会得到 N 个 bin。

with sample_data as
    (select 
        rownum as id,
        case when rownum <= 50 then 0 else rownum end as value
    from xmltable('1 to 100')
    )
select 
    id,
    value,
    ntile(50) over (order by value) as ntile_v1,
    case when value = 0 then 0 else ntile(50) over (order by value) end as ntile_v2
from sample_data
order by id;

一个解决方案是将非零值放入单独的 CTE,计算那里的图块,然后返回:

with sample_data as
    (select 
        rownum as id,
        case when rownum <= 50 then 0 else rownum end as value
    from xmltable('1 to 100')
    )
, sample_data_not_zero as
    (select 
        id, 
        value, 
        ntile(50) over (order by value) as ntile_v3 
    from sample_data 
    where value <> 0
    )
select 
    sd.id,
    sd.value,
    nvl(sdnz.ntile_v3, 0) as ntile_v3
from 
    sample_data sd
    left outer join
    sample_data_not_zero sdnz on sd.id = sdnz.id
order by id;

不幸的是,我必须为许多不同的列计算这个,我想知道是否有更短的解决方案。

除了当前的 case 表达式之外,您还可以根据零对 ntile 与 non-zero 进行分区:

case
  when value = 0 then 0
  else ntile(50) over (partition by case when value = 0 then 0 else 1 end order by value)
end as ntile_v3

这似乎与您的 union 查询得到相同的结果。

db<>fiddle