I am trying to create a simple function that returns the least value passed to the function... but when running it doesn't work it just returns the same values I pass into the function 15,2,3 which should return 2... can someone help me and tell me why it doesn't work?
CREATE OR REPLACE
function
GET_LEAST_VALUE(in_numbers IN VARCHAR2)
RETURN VARCHAR2
IS
vReturn varchar2(50);
BEGIN
vReturn := least(in_numbers);
return vReturn;
END;
CodePudding user response:
As commented, it can't work as you're actually passing a string to the function.
Here's one option - it splits that string into rows; regexp_substr
returns a string (again) so - trim it first (to remove possible spaces) and apply to_number
(otherwise you'd compare strings, and that's different from comparing numbers). Finally, apply the min
aggregate function because least
won't work if you passed more than a single number (you'd get too_many_rows error).
SQL> CREATE OR REPLACE FUNCTION get_least_value (in_numbers IN VARCHAR2)
2 RETURN VARCHAR2
3 IS
4 vreturn VARCHAR2 (50);
5 BEGIN
6 WITH
7 temp
8 AS
9 ( SELECT TO_NUMBER (TRIM (REGEXP_SUBSTR (in_numbers,
10 '[^,] ',
11 1,
12 LEVEL))) val
13 FROM DUAL
14 CONNECT BY LEVEL <= REGEXP_COUNT (in_numbers, ',') 1)
15 SELECT MIN (val)
16 INTO vreturn
17 FROM temp;
18
19 RETURN vreturn;
20 END;
21 /
Function created.
SQL> SELECT get_least_value ('15,2,3') result FROM DUAL;
RESULT
--------------------------------------------------------------------------------
2
SQL>
CodePudding user response:
CREATE OR REPLACE FUNCTION get_least_value (in_numbers IN VARCHAR2) RETURN NUMBER IS
w_result NUMBER ;
BEGIN
SELECT MIN(value) INTO w_result FROM
json_table (
'[' || in_numbers || ']',
'$[*]'
columns (
value NUMBER PATH '$'
)
)
;
RETURN w_result ;
END ;
/
SELECT get_least_value('4,1,9,0,-5') from dual ;
-5
CodePudding user response:
Why it doesn't work?
It does work as you pass in a single string and LEAST
finds the least value when comparing that single string to nothing else so it returns that single string; which is exactly what LEAST
is intended to do.
However, it is not what you expect it to do.
Why does it not do what I expect?
You are expecting '15,2,3'
to be evaluated as a list of numbers (i.e. LEAST(15,2,3)
) but it is not a list of numbers it is a single string literal that happens to look, to a human, like a list of numbers but, to the SQL engine, it is actually only one string value and will be evaluated as LEAST('15,2,3')
.
How to fix it?
You need to either pass in multiple values via a collection (for example, the built-in SYS.ODCINUMBERLIST
varray collection type):
CREATE FUNCTION GET_LEAST_VALUE(
in_numbers IN SYS.ODCINUMBERLIST
) RETURN NUMBER
IS
v_least NUMBER;
BEGIN
SELECT MIN(column_value)
INTO v_least
FROM TABLE(in_numbers);
RETURN v_least;
END;
/
and then call it as:
SELECT get_least_value(SYS.ODCINUMBERLIST(15,2,3))
FROM DUAL;
or
BEGIN
DBMS_OUTPUT.PUT_LINE(get_least_value(SYS.ODCINUMBERLIST(15,2,3)));
END;
/
Or alternatively, you need to split the string into separate values and then find the minimum of those values.