using sys_context to match data string - oracle

I'm trying to use data in sys_context form to perform a match in a WHERE clause.
What I put into the context is ('53','89'), which is what is returned when I select against dual.
My where statement is: where to_char(location_id) in sys_context('my_ctx','valoc')
Since I'm not getting the expected response, I'm guessing that what I think Oracle should see is not actually what it sees, but I don't know how to "look" at what's passed to the processor from TOAD.
The original form was where location_id in sys_context('my_ctx','valoc') with (53,89) in valoc, but that didn't return anything either. I'm sensing there may be no answer to my problem.

The problem is that the resulting WHERE clause is equivalent to this:
where to_char(location_id) in '('53','89')'
(didn't double the inner apostrophes for clarity)
The database sees what's retrieved from context as a single value, not as a list of values.
You can use the CONNECT BY trick to achieve your goal:
SELECT 1
FROM dual
WHERE '53' IN ( -- replace '53' with TO_CHAR(location_id)
SELECT regexp_substr('53,89', '[0-9]*', 1, level) -- replace '53,89' with sys_context('my_ctx','valoc')
FROM dual
CONNECT BY regexp_substr('53,89', '[0-9]*', 1, level) IS NOT NULL -- replace '53,89' with sys_context('my_ctx','valoc')
);

Related

What is exactly difference between a 'statement' and a 'function' in oracle sql?

While reading upon the difference between decode function and CASE WHEN statement, I got confused while understanding that if both give the same result for a simple equation like the following:
DECODE(col1, 'ABC', 'DEF', 'OTHERS' ) AS COL2
CASE WHEN COL1 = 'ABC' THEN 'DEF'
ELSE 'OTHERS'
END AS COL2
Then what is the difference between the functionality of a function and a statement?
p.s. I am aware Case is capable of taking more complex equations... my question here is more about understanding difference between function and statement.
In SQL, there is no such thing as a "CASE statement". Your example is a CASE expression. (CASE statements do exist in PL/SQL.)
The documentation states "An expression is a combination of one or more values, operators, and SQL functions that evaluates to a value." So a SQL function is not different from an expression, it is a specific type of expression.
Note that DECODE and CASE behave differently when comparing NULL values: DECODE considers two NULLs to be "the same", which is an exception to the rule that comparing a NULL to anything has an "unknown" result.
with data(a, b) as (
select 1,1 from dual union all
select 1,null from dual union all
select null,1 from dual union all
select null, null from dual
)
select a, b,
decode(a,b,'same','different') decode_result,
case when a = b then 'same' else 'different' end case_result
from data;
A B DECODE_RESULT CASE_RESULT
------ ------ ------------- -----------
1 1 same same
1 (null) different different
(null) 1 different different
(null) (null) same different
I'm pretty much sure that CASE didn't exist in pre-9i Oracle database versions so you had to use DECODE.
No difference, they will both do the same job, but CASE is simpler to maintain. DECODE can grow to a real monster when complex things have to be done, with nested DECODEs so you probably know what you're doing while typing that statement, but a month later you're in deep trouble as you don't know what belongs to what, which closing bracket is closing which open bracket, ... real nightmare.
But, for simple things, it is quite OK. Saves some typing.
A function is simply some functionality capsuled. With a function you can call a functionality from anywhere without spelling it out explicitely. There are predefined functions like DECODE() or you can define functions yourself.
A statement is something like select 1 from dual and may contain functions (select decode(col1,'1','yes','no') from mytable).
The statement is (as long as you aren't in a block, which itself may contain several statements) an order you send to the DB, a function is kindof an instruction what to do with the given arguments.

pl/sql save hierarchical query to variable

I am trying to save result set of hierarchical query to variable
CREATE OR REPLACE FUNCTION test12
RETURN number IS
result number(4):=0;
clli_array dbms_sql.varchar2_table;
BEGIN
with tmp as (select 'strforregexp' str from dual)
select regexp_substr(str, '\/([A-Z0-9]{11}|[A-Z0-9]{8})', 1, level) STR into :clli_array from tmp
connect by regexp_substr(str, '\/([A-Z0-9]{11}|[A-Z0-9]{8})', 1, level) is not null;
END test12;
But getting an error
Error(9,9): PLS-00049: bad bind variable 'CLLI_ARRAY'
So, i have 2 questions
1) can i get all matches of regexp witohout hierarchical query
2) why i am getting an error
As #APC pointed out, the first problem is that you've got a colon in front of CLLI_ARRAY. This causes the PL/SQL compiler to believe that CLLI_ARRAY is going to be a SQL*Plus substitution variable, and when it finds that such a variable is not defined it throws the error you got.
However, even if you remove the colon you're not out of the woods yet. Once you remove the colon you'll get
PLS-00597: expression 'CLLI_ARRAY' in the INTO list is of wrong type
That's because CLLI_ARRAY is a PL/SQL-type collection, but your statement returns a single string.
What you probably want to do is to use BULK COLLECT to have the system retrieve all the results of the query into your VARCHAR2_TABLE:
with tmp as (select 'strforregexp' str from dual)
select regexp_substr(str, '\/([A-Z0-9]{11}|[A-Z0-9]{8})', 1, level) STR
BULK COLLECT into clli_array
from tmp
connect by regexp_substr(str, '\/([A-Z0-9]{11}|[A-Z0-9]{8})', 1, level) is not null
Best of luck.

Oracle invalid number in clause

I'm struggling with getting a query to work, and I could really use some help. We have an in house app that we use for building small web apps where I work. It's basically a drag and drop GUI. There's functionality built in to access query string values using the key.
I'm passing a comma separated list of values into a page through the query string. I'm then trying to use the list of values as part of an in clause in a query.
I can see that the value is correct in the query string.
orders=1,2,3
Here's the specific part of the query
"AND OrderNumber IN (this is where it maps from the query string)
I've tried running similar queries in Toad, and I think I've found the issue. It's giving an invalid number error, and I think it's wrapping the query string value in single quotes. I can replicate the error when I do "AND OrderNumber IN ('1,2,3')" in Toad.
Here's where I get really confused. The following works in Toad.
"AND OrderNumber IN ('1','2','3')"
So I tried recreating that by doing
select replace('1,2,3', ',', chr(39)||','||chr(39)) from dual;
I have confirmed that returns '1','2','3' in Toad.
However, I still get an Invalid Number error when I run the following in Toad.
AND OrderNumber IN (replace('1,2,3', ',', chr(39)||','||chr(39))
I've been racking my brain over this, and I can't figure it out. It seems to me that if "AND OrderNumber IN ('1','2','3')" works, and replace('1,2,3', ',', chr(39)||','||chr(39)) returns '1','2','3', that "AND OrderNumber IN (replace('1,2,3', ',', chr(39)||','||chr(39))" should work.
Any help you might be able to offer on this would be greatly appreciated. I know the rest of the query works. That's why I didn't post it. I'm just stuck on trying to get this IN clause working.
A change to phonetic_man's answer that will allow for NULL elements in the list. The regex format of '[^,]+' for parsing delimited lists does not handle NULL list elements and will return an incorrect value if one exists and thus its use should be avoided. Change the original by deleting the number 2 for instance and see the results. You will get a '3' in the 2nd element's position! Here's a way that handles the NULL and returns the correct value for the element:
SELECT TRIM(REGEXP_SUBSTR(str, '(.*?)(,|$)', 1, LEVEL, NULL, 1)) str
FROM ( SELECT '1,,3,4' str FROM dual )
connect by level <= regexp_count(str, ',') + 1;
See here for more info and proof: https://stackoverflow.com/a/31464699/2543416
Can you try the following query.
SELECT * FROM orders
WHERE orderno IN
(
SELECT TRIM(REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL)) str
FROM ( SELECT '1,2,3,4' str FROM dual )
CONNECT BY INSTR(str, ',', 1, LEVEL - 1) > 0
)
The inline query splitting the string in different rows. So, on executing it you will get the following result.
SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str
FROM ( SELECT '1,2,3,4' str FROM dual )
CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0
1
2
3
4
Now, passing this result to the main query IN clause should work.
I think the desired clause to be built is:
AND OrderNumber IN (1,2,3)
A numeric list. The example you tested:
AND OrderNumber IN ('1','2','3')
works because an implicit conversion from a VARCHAR2 to a NUMBER is occurring for each element in the list.
The following clause will not work because no implicit conversion of the string '1,2,3' can be made (note the clause has a single string element):
AND OrderNumber IN ('1,2,3')
When doing a replace, you are converting the single string: 1,2,3 with the single string: 1','2','3 and this single string cannot be implicitly converted to a number.

How CONNECT BY in subquery works

I have a query as below
select substr( 'ORACLE DEVELOPER',level,1 ) ITEM
from dual connect by level <= length('ORACLE DEVELOPER') ;
it returns 'O' as the result.
but if i put this as a subquery in other it is displaying the required output.
query is as below.
select a.ITEM from (select substr( 'ORACLE DEVELOPER',level,1 ) ITEM
from dual connect by level <= length('ORACLE DEVELOPER') ) a
How this CONNECT BY is working in subquery.
I am new to this feature. Can anyone explain this??
CONNECT BY is Oracle SQL syntax for doing hierarchical queries. Some good examples are here.
One of the side effects is that it allows you to query a single data source multiple times, which means that there's a handy trick to generate any number of rows with:
SELECT 1
FROM dual
CONNECT BY LEVEL <= 10;
The above will connect dual back to itself 10 times - the LEVEL pseudocolumn is from the hierarchy; because the CONNECT BY clause doesn't actually refer to any data from the rowsource, it effectively makes dual its own child, grandchild, great-grandchild, etc. until the CONNECT BY clause evaluates to false (in this case, when LEVEL becomes greater than 10).
In your case, you are generating a row for each letter of the string (instead of 10, you are referring to LENGTH('a string'), which is a nice way of getting a query to return one record for each letter in the string. You are then using SUBSTR to pick out the nth letter from the string.

Select pkg_name.function_name

Is this query valid? if the package(with proper definition and body) and function exists and works fine.
Select "JK" As Name,
pckg_name1.function_name1(number1,number2)
from dual
The function call is fine (assuming the function returns a SQL data type - you cannot use PL/SQL specific data types, e.g. Boolean), but your quoting for JK is wrong. You have to use single quotes instead of double ones:
Select 'JK' As Name,
pckg_name1.function_name1(number1,number2)
from dual

Resources