简体   繁体   中英

select to get rows based on minimum value of a column

I have a table WT_RT.

a select on it will give me this result

select * from WT_RT;
    WT_SEQ W     RT_AMT R
---------- - ---------- -
         0 0        125 M
         1 2        9.3 N
        45 2       7.19 Q
       100 1       6.38 Q
       300 1       5.11 Q
       500 2       4.69 Q
      1000 2       4.39 Q

On input of WT_SEQ=250 , since 250 is in between 100 and 300 I need to select the row which has the least RT_AMT . In this case, since 5.11 < 6.38 , I need to select the row with WT_SEQ = 300.

Expected Result:

    WT_SEQ W     RT_AMT R
---------- - ---------- -
       300 1       5.11 Q

So far I have managed to find the enclosing 2 rows.

 select ........;
    WT_SEQ W     RT_AMT R
---------- - ---------- -
       100 1       6.38 Q
       300 1       5.11 Q

But I need to implement the condition of minimum value of RT_AMT How to do it?

One way is via a top 2 of an order by distance.
Then the top 1 of an order by RT_AMT.

select WT_SEQ, RT_AMT
from
(
  select *
  from
  (
    select * 
    from WT_RT
    cross join (select 250 val from dual) v
    order by ABS(WT_SEQ - val)
  ) q1
  where rownum <= 2
  order by (case when WT_SEQ = val then 1 else 2 end), RT_AMT asc
) q2
where rownum = 1;

The CASE WHEN is added to give priority to an WT_SEQ that's equal to the value.

You can try to write a subquery to get nextval by LEAD then, use BETWEEN to get between WT_SEQ column, then self join by WT_SEQ

then use Row_NUMBER with Windows Function to make Rownumber by RT_AMT , then get rn = 1

TestDLL

CREATE TABLE WT_RT(
WT_SEQ INT,
  RT_AMT FLOAT
);
INSERT INTO WT_RT VALUES (0,125);
INSERT INTO WT_RT VALUES (   1, 9.3);
INSERT INTO WT_RT VALUES (  45,7.19);
INSERT INTO WT_RT VALUES ( 100,6.38);
INSERT INTO WT_RT VALUES ( 300,5.11);
INSERT INTO WT_RT VALUES ( 500,4.69);
INSERT INTO WT_RT VALUES (1000,4.39);

Query

WITH CTE1 AS(
  SELECT t2.WT_SEQ,t2.RT_AMT,Row_NUMBER() OVER(ORDER BY t2.RT_AMT) rn 
  FROM (
    SELECT * FROM (
      SELECT t1.*,LEAD(WT_SEQ,1,WT_SEQ) over(order by WT_SEQ) nextval
      FROM WT_RT t1
    )t1
    WHERE 250 BETWEEN WT_SEQ and nextval
  ) t1 INNER JOIN WT_RT t2
  on t1.WT_SEQ = t2.WT_SEQ or t1.NEXTVAL = t2.WT_SEQ 
)
SELECT * 
FROM CTE1
WHERE RN = 1

sqlfiddle

[Results] :

| WT_SEQ | RT_AMT | RN |
|--------|--------|----|
|    300 |   5.11 |  1 |

You can just use aggregation:

select MIN(RT_AMT)
from WT_RT
where WT_SEQ <= 250

If you need the entire row, you can select one row. In Oracle 12C+:

select MIN(RT_AMT)
from WT_RT
where WT_SEQ <= 250
order by WT_SEQ desc
fetch first 1 row only;

In older version:

select x.*
from (select MIN(RT_AMT)
      from WT_RT
      where WT_SEQ <= 250
      order by WT_SEQ desc
     ) x
where rownum = 1;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM