ORACLE Obtain the greater and lower value in a varchar2 field range - oracle

I have a table with a field varchar2 type,
Suppose this values:
aaab
s123
2445
25
21000
2500000
1
10000790
1899
I need to obtain the greater value that begins with 2.
I was trying with:
Select TO_NUMBER(myfield) from Services where myfield like '2%';
I get
2445
25
21000
2500000
Now, I want to obtain, the greater and the smaller values 25 and 2500000.
I was trying with:
Select TO_NUMBER(myfield) from Services where myfield like '2%' ORDER BY myfield DESC;
and
Select MAX(TO_NUMBER(myfield)) from Services where myfield like '2%';
Select MIN(TO_NUMBER(myfield)) from Services where myfield like '2%';
I get:
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.

Oracle executes most function calls regardless if the row is part of the result set or not. To ensure that the function is only called for values of the result set put the where condition in a subquery:
Select TO_NUMBER(myfield)
from (SELECT * from Services where myfield like '2%')
ORDER BY 1 DESC
If you are not sure, that every value of your table is a number it would be better to write your own pl/sql function:
CREATE FUNCTION my_to_number(val IN VARCHAR2) RETURN NUMBER IS
BEGIN
RETURN TO_NUMBER(val);
EXCEPTION
WHEN VALUE_ERROR THEN
RETURN NULL;
END;
And then use this function to get your values:
Select MY_TO_NUMBER(myfield)
from Services where myfield like '2%'
ORDER BY 1 DESC

Related

PLSQL aggregation function using type object PARALLEL_ENABLE AGGREGATE

I have question. Already i have avg_new function, which include nulls (as 0) in the result. I have start from linkedin link.
Code:
select avg(a),avg_new(nvl(a,-9999)) from
(select 'test' h, 2 a from dual
union all
select 'test' h, null a from dual
union all
select 'test' h, 2 a from dual
union all
select 'test' h ,2 a from dual)
the results are
2; 1,5
I would like to extend avg_new function by adding denominator parameter ex.:
avg_new(nvl(a,-9999),10)
Te result should be then 0.6
Default value of the parameter would be null, then function works as previous example. If the parameter would be >0 then I would divide sum of 'a' by value of this parameter. How i could do this? I would like to pass this parameter to used type object and to perform further calculations there. Is it possible?
create or replace FUNCTION avg_new (input NUMBER , denominator NUMBER DEFAULT NULL) RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING T_avg_new;
Right now the type could proper read only the first parameter. After adding i have errors:
ORA-29925: cannot execute T_avg_new.ODCIAGGREGATEINITIALIZE
ORA-06553: PLS-306: wrong number or types of arguments in call to "ODCIAGGREGATEINITIALIZE"
00000 - "cannot execute %s"
*Cause: The specified function does not exist or does not have an
appropriate signature.
*Action: Implement the function with the appropriate signature.

Trying to display top 3 amount from a table using sql query in oracle 11g..column is of varchar type

Am trying to list top 3 records from atable based on some amount stored in a column FTE_TMUSD which is of varchar datatype
below is the query i tried
SELECT *FROM
(
SELECT * FROM FSE_TM_ENTRY
ORDER BY FTE_TMUSD desc
)
WHERE rownum <= 3
ORDER BY FTE_TMUSD DESC ;
o/p i got
972,9680,963 -->FTE_TMUSD values which are not displayed in desc
I am expecting an o/p which will display the top 3 records of values
That should work; inline view is ordered by FTE_TMUSD in descending order, and you're selecting values from it.
What looks suspicious are values you specified as the result. It appears that FTE_TMUSD's datatype is VARCHAR2 (ah, yes - it is, you said so). It means that values are sorted as strings, not numbers - and it seems that you expect numbers. So, apply TO_NUMBER to that column. Note that it'll fail if column contains anything but numbers (for example, if there's a value 972C).
Also, an alternative to your query might be use of analytic functions, such as row_number:
with temp as
(select f.*,
row_number() over (order by to_number(f.fte_tmusd) desc) rn
from fse_tm_entry f
)
select *
from temp
where rn <= 3;

Oracle query result as JSON

I'm working in Oracle 12.2.
I've got a complex query the results of which I would like to receive as a CLOB in JSON format. I've looked into json_object, but this means completely rewriting the query.
Is there a way to simply pass the ref cursor or result set and receive a JSON array with each row being a JSON object inside?
My query:
SELECT
*
FROM
(
SELECT
LABEL_USERS.*,
ROWNUM AS RANK ,
14 AS TOTAL
FROM
(
SELECT DISTINCT
SEC_VS_USER_T.USR_ID,
SEC_VS_USER_T.USR_FIRST_NAME,
SEC_VS_USER_T.USR_LAST_NAME,
SEC_USER_ROLE_PRIV_T.ROLE_ID,
SEC_ROLE_DEF_INFO_T.ROLE_NAME,
1 AS IS_LABEL_MANAGER,
LOWER(SEC_VS_USER_T.USR_FIRST_NAME ||' '||SEC_VS_USER_T.USR_LAST_NAME) AS
SEARCH_STRING
FROM
SEC_VS_USER_T,
SEC_USER_ROLE_PRIV_T,
SEC_ROLE_DEF_INFO_T
WHERE
SEC_VS_USER_T.USR_ID = SEC_USER_ROLE_PRIV_T.USR_ID
AND SEC_VS_USER_T.USR_SITE_GRP_ID IS NULL
ORDER BY
UPPER(USR_FIRST_NAME),
UPPER(USR_LAST_NAME)) LABEL_USERS) LABEL_USER_LIST
WHERE
LABEL_USER_LIST.RANK >= 0
AND LABEL_USER_LIST.RANK < 30
I couldn't find a procedure which I could use to generate the JSON, but I was able to use the new 12.2 functions to create the JSON I needed.
SELECT JSON_ARRAYAGG( --Used to aggregate all rows into single scalar value
JSON_OBJECT( --Creating an object for each row
'USR_ID' VALUE USR_ID,
'USR_FIRST_NAME' VALUE USR_FIRST_NAME,
'USR_LAST_NAME' VALUE USR_LAST_NAME,
'IS_LABEL_MANAGER' VALUE IS_LABEL_MANAGER,
'SEARCH_STRING' VALUE SEARCH_STRING,
'USR_ROLES' VALUE USR_ROLES
)returning CLOB) AS JSON --Need to cpecify CLOB, otherwise the result is limited by VARCHARC2(4000)
FROM
(
SELECT * FROM (
SELECT LABEL_USERS.*, ROWNUM AS RANK, 14 AS TOTAL from
(SELECT
SEC_VS_USER_T.USR_ID,
SEC_VS_USER_T.USR_FIRST_NAME,
SEC_VS_USER_T.USR_LAST_NAME,
1 AS IS_LABEL_MANAGER,
LOWER(SEC_VS_USER_T.USR_FIRST_NAME ||' '||SEC_VS_USER_T.USR_LAST_NAME) AS SEARCH_STRING,
(
SELECT --It is much easier to create the JSON here and simply use this column in the outer JSON_OBJECT select
JSON_ARRAYAGG(JSON_OBJECT('ROLE_ID' VALUE ROLE_ID,
'ROLE_NAME' VALUE ROLE_NAME)) AS USR_ROLES
FROM
(
SELECT DISTINCT
prv.ROLE_ID,
def.ROLE_NAME
FROM
SEC_user_ROLE_PRIV_T prv
JOIN
SEC_ROLE_DEF_INFO_T def
ON
prv.ROLE_ID = def.ROLE_ID
ORDER BY
ROLE_ID DESC)) AS USR_ROLES
FROM
SEC_VS_USER_T,
SEC_USER_ROLE_PRIV_T,
SEC_ROLE_DEF_INFO_T
WHERE
SEC_VS_USER_T.USR_ID = SEC_USER_ROLE_PRIV_T.USR_ID
AND SEC_USER_ROLE_PRIV_T.ROLE_PRIV_ID = SEC_ROLE_DEF_INFO_T.ROLE_ID
AND SEC_VS_USER_T.USR_SITE_GRP_ID IS NULL
ORDER BY UPPER(USR_FIRST_NAME),
UPPER(USR_LAST_NAME))LABEL_USERS)) LABEL_USER_LIST
WHERE LABEL_USER_LIST.RANK >= 0--:bv_Min_Rows
AND LABEL_USER_LIST.RANK < 30--:bv_Max_Rows

Enumerate and add in a column of the select - Oracle

I need to enumerate my lines in a column of the select by a type. For example, I have three types which can be "RR", "RJ" and "RA", every time that a type "RR" appears I have to sum 3 and the other ones I have to sum only 1, creating a sequence like:
Type Number
RR 3
RR 6
RJ 7
RR 10
RJ 11
RA 12
RR 15
I have other fields in the select, so I used the ROW_NUMBER() function with all my order by fields, something like:
select
number,
[...]
type,
ROW_NUMBER() OVER (order by number, type [...] )*3 as sequence
from
my_table
order by number, type [...]
I also tried to use a case statement, but it doesn't aggregate the values.
Is it possible to do? I'm trying to use the ROW_NUMBER() function, but i can't get the result, only three by three.
You could use SUM:
select
number,
[...]
type,
SUM(CASE WHEN Type = 'RR' THEN 3 ELSE 1 END)
OVER (order by number, type [...] ) as sequence
from my_table
order by number, type [...]
Rextester Demo

Expected CHAR got NUMBER

DB: Oracle 11g
Query:
SELECT CASE
WHEN rs.OPTION = '3'
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID
)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID
)
END AS PROPTS
FROM PR_OPTS
I am getting error 'expected CHAR got NUMBER', here EXTS,GROUP_ID & GRP_ID are numeric. Then how there is a chance of expecting CHAR?
Generally when Oracle compares different datatypes such as a NUMBER with a CHARACTER, implicit conversion kicks in and all is well (provided the data can be converted.) For example, if you have a function that expects a CHARACTER value but you pass it a NUMBER, all is well - Oracle simply converts the NUMBER to character.
E.g. a function like this:
create or replace function get_something(p_id VARCHAR2) return number ...
works if you call it with this:
get_dno(10);
or this:
get_dno('10');
and in SQL:
select * from some_table where numeric_column = '10' -- no problem.
A popular place where you see this kind of error is with the return values in CASE statements. For instance, you'll get that error if you have something like this:
SQL> SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
2 FROM dual
3 ;
SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected CHAR got NUMBER
(The datatype from the first WHEN clause is what it expects in the other WHEN/ELSE clauses that follow.)
But in your case the WHEN and THEN both return counts - the datatypes are consistent. So, I think you have a red-herring in there.
As Alex mentioned above, OPTION is a keyword and if you try and create a table with that as a column name, Oracle disagrees:
SQL> create table dummy
2 (option varchar2(10)
3 );
(option varchar2(10)
*
ERROR at line 2:
ORA-00904: : invalid identifier
This works:
SQL> create table dummy
2 (option_col varchar2(10)
3 );
Table created.
or you could do it with quotes:
SQL> create table dummy
2 ("option" varchar2(10));
Table created.
But now you're in a world of hurt - you need quotes from now on:
SQL> select option from dummy;
select option from dummy
*
ERROR at line 1:
ORA-00936: missing expression
SQL> select d.option from dummy d;
select d.option from dummy d
*
ERROR at line 1:
ORA-01747: invalid user.table.column, table.column, or column specification
With quotes:
SQL> select d."option" from dummy d;
no rows selected
So, if your query is really giving you "expected CHAR, got NUMBER", it looks to me like something is off.
Essentially, it means some of the fields you are using aren't compatible with each other. It's basically a "type mismatch". Just check to see if any types of CHAR are being used with types of NUMBER. Then you can either switch the type of one, or simply use a conversion as part of the query.
The issue is OPTION = '3', the quotation marks indicate that you're looking for a string containing the solitary character 3.
Try this instead:
SELECT CASE
WHEN rs.OPTION = 3
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID)
END AS PROPTS
FROM PR_OPTS

Resources