× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



On 05-Dec-2013 12:31 -0800, Koester, Michael wrote:
I know I can solve this by fetching through a cursor, but I thought
I'd toss this up for someone to introduce me to a function that I've
not yet discovered:

I need the row where a numeric column contains a number closest to
(either greater or less than) a specified value.
Example: I want the row where ColumnA is closest to 1580.
Row# ColumnA
1 2016
2 1527
3 1874
4 4769
5 1600
6 158

Since there is no row with '1580', I would accept row 5, which is
the closest. If there were two rows where the difference from the
target value is the same (like if row 7 was added where ColumnA was
1560), I'd prefer the larger ColumnA value.

FWiW, this topic is not specific to the RPG; i.e. could just as well have been started on the midrange-l instead.

No mention of which row to choose if there are multiple equidistant values found. Or maybe there is a unique index on ColumnA?

If there is a keyed-access-path\index for the ColumnA, then the following query should enable the query engine to avoid processing all rows of the table; i.e. the use of two index [index-only seems likely] accesses to find the specific values of ColumnA in the file that are either equal to the input value or the nearest lower value or the nearest higher value, and then retrieval by that index for the specific rows of those eligible. Given unique values across ColumnA there could be only one or two eligible rows possible. But if not unique, then there could be many possible matches; ordering by the Row# column might be necessary as I alluded originally above.?

Setup used to test; too small for costing tending toward an AccPth implementation:

create table qtemp/filefc (row# dec(2), columna dec)
;
insert into qtemp/filefc values
( 1, 2016 )
,( 2, 1527 )
,( 3, 1874 )
,( 4, 4769 )
,( 5, 1600 )
,( 6, 158 )
,( 7, 1876 )
,( 8, 1876 )
,( 9, 1876 )
,( 10, 1513 )
; -- 10 rows inserted in FILEFC in QTEMP.
create index filefcix on qtemp/filefc (columna desc)
; -- Index FILEFCIX created in QTEMP on table FILEFC in QTEMP.

Test with input values, to include boundaries, equal, equidistant, equidistant and duplicates:

:nearToVal = 5000 4769 3000 1520 1776 1876 1875 1580 0200 158 003
:resultVal = 4769 4769 2016 1527 1874 1876 1876 1600 0158 158 158
:resultRow#= 4 4 1 2 3 7± 7± 5 6 6 6
EligibleRows= 1 1 2 2 2 3 4 2 2 1 1
OtherRowVal= - - 4769 1513 1600 1876 1874 1527 1513 - -
±the result is unpredictable, without ordering on Row#

If there is no constraint preventing negative values, some tests with negative values perhaps should be added.

While the following queries look and indeed are, _more complex_ than the other query already offered in the thread, I expect if there is a large amount of data in the file, then the implementation [access plan] of the following queries might enable either query to perform much faster than a query that both selects and orders on an expression over all rows. The following queries should perform the expression [absolute value of the result of the column-value minus the input value] and ordering only on the already-retrieved data from the [likely just one or two] rows rather than having to perform that expression and collation by its result for every row:


select y.*
from
( values( (select min(s.columna) from qtemp/filefc s
where s.columna >= :nearToVal )
, (select max(s.columna) from qtemp/filefc s
where s.columna <= :nearToVal )
) as x ( higherVal, lesserVal ) /* don't let min\max fool you */
, lateral /* implied cross join with the above one-row table */
( select s.* , abs( s.columna - :nearToVal ) as diffVal
from qtemp/filefc s
where s.columna in ( x.lesserVal, x.higherVal )
) y
order by diffVal asc
, columna desc
/* , row# desc -- latest row? */
fetch first 1 row only /* implicitly then: optimize for 1 row */


with
minmax (minmaxVal) as
( (select min(s.columna) from qtemp/filefc s
where s.columna >= :nearToVal )
union (select max(s.columna) from qtemp/filefc s
where s.columna <= :nearToVal )
) /* UNION ALL acceptable too; but for consistent */
/* test results to matrix above, without fetch first */
select s.* , abs( s.columna - :nearToVal ) as diffVal
from minmax x
left join qtemp/filefc s
on minmaxVal = s.columna
where minmaxVal is not null /* optional; but for consistent */
/* test results to matrix above, without fetch first */
order by diffVal asc
, columna desc
/* , row# desc -- latest row? */
fetch first 1 row only /* implicitly then: optimize for 1 row */



As an Amazon Associate we earn from qualifying purchases.

This thread ...

Follow-Ups:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.