在SQL中查找最接近或更高的值

时间:2016-09-13 10:10:01

标签: sql oracle

我有一张桌子:

表1

rank  value
1     10
25    120
29    130
99    980

我必须生成下表:

表2

rank  value
1     10
2     10
3     10
4     10
5     10
6     10
7     10
8     10
9     10
10    10
11    10
12    10
13    120
14    120
15    120
.
.
.
.
25    120
26    120
27    130
28    130
29    130
30    130
.
.
.
.
.
62    980
63    980
.
.
.
99    980
100   980

因此,table2应该具有从1到100的所有值。有3种情况:

  • 如果它完全匹配,例如等级25,值为120
  • 查找最接近的,例如对于表2中的等级9,我们没有精确匹配,但1最接近9(9-1 = 8而25-9 = 16),因此赋值为1
  • 如果双方的分配相同,则使用更高的等级值,例如对于等级27,我们有25个以及29个等距离,所以取更高的值,即29并赋值。

5 个答案:

答案 0 :(得分:3)

类似

-- your testdata
with table1(rank,
value) as
 (select 1, 10
    from dual
  union all
  select 25, 120
    from dual
  union all
  select 29, 130
    from dual
  union all
  select 99, 980
    from dual),
-- range 1..100
data(rank) as
 (select level from dual connect by level <= 100)

select d.rank,
       min(t.value) keep(dense_rank first order by abs(t.rank - d.rank) asc, t.rank desc)
  from table1 t, data d
 group by d.rank;

答案 1 :(得分:0)


您可以使用交叉连接。使用以下查询来获得结果

select t1.* from table1 t1 
cross join
(select * from table1) t2
on (t1.rank=t2.rank);

希望你明白了

答案 2 :(得分:0)

如果我理解您的需要,您可以使用以下内容:

select num, value
from (
        select num, value, row_number() over (partition by num order by abs(num-rank) asc, rank desc) as rn
        from table1
          cross join ( select level as num from dual connect by level <= 100) numbers
     )
where rn = 1

这会将你的表与[1,100]区间连接起来,然后只保留每个数字的第一行,按差异排序,并保持相等差异的最大值。

答案 3 :(得分:0)

使用您的表加入分层数字生成器,并使用带有lag()子句的ignore nulls

select h.rank, case when value is null 
                    then lag(value ignore nulls) over (order by h.rank) 
                    else value 
               end value
  from (select level rank from dual connect by level <= 100) h 
  left join t on h.rank = t.rank
  order by h.rank

测试:

with t(rank, value) as ( 
                        select  1,  10 from dual union all
                        select 25, 120 from dual union all
                        select 29, 130 from dual union all 
                        select 99, 980 from dual )
select h.rank, case when value is null 
                    then lag(value ignore nulls) over (order by h.rank) 
                    else value 
               end value
  from (select level rank from dual connect by level <= 100) h 
  left join t on h.rank = t.rank
  order by h.rank

      RANK       RANK
---------- ----------
         1         10
         2         10
...
        24         10
        25        120
        26        120
        27        120
        28        120
        29        130
        30        130
...
        98        130
        99        980
       100        980

答案 4 :(得分:0)

这是一个不需要交叉连接的替代方案(但确实使用了一些分析函数,因此您需要测试这是否比您的数据集更高效)其他解决方案):

WITH sample_data AS (SELECT 1 rnk, 10 VALUE FROM dual UNION ALL
                     SELECT 25 rnk, 120 VALUE FROM dual UNION ALL
                     SELECT 29 rnk, 130 VALUE FROM dual UNION ALL
                     SELECT 99 rnk, 980 VALUE FROM dual)
SELECT rnk + LEVEL - 1 rnk,
       CASE WHEN rnk + LEVEL - 1 < rnk + (next_rank - rnk)/2 THEN
                 VALUE
            ELSE next_value
       END VALUE
FROM   (SELECT rnk,
               VALUE,
               LEAD(rnk, 1, 100 + 1) OVER (ORDER BY rnk) next_rank,
               LEAD(VALUE, 1, VALUE) OVER (ORDER BY rnk) next_value
        FROM   sample_data)
CONNECT BY PRIOR rnk = rnk
           AND PRIOR sys_guid() IS NOT NULL
           AND LEVEL <= next_rank - rnk;

       RNK      VALUE
---------- ----------
         1         10
         2         10
       ...        ...
        12         10
        13        120
       ...        ...
        24        120
        25        120
        26        120
        27        130
        28        130
        29        130
        30        130
       ...        ...
        63        130
        64        980
        65        980
       ...        ...
        98        980
        99        980
       100        980

N.B,我不确定你为什么62和63的值为980 - 29到99之间的中点是64.

此外,您还会看到我使用100 + 1代替101 - 这是因为如果您想要对事物进行参数设置,则应将100替换为v_max_rank + 1参数 - 例如 Title Firstname Lastname Telephone Initial Gender More columns 1 Mr Adam Smith 001 2 Mrs Angela Evans 002 AE 3 Mr Bill Towny 003 4 Miss Dame Beaut 004