Pl/SQL query a view in function - oracle

I have the function below
CREATE OR REPLACE FUNCTION BUTCE_REPORT_Fun (birim_id IN VARCHAR2)
RETURN sys_refcursor
IS
retval sys_refcursor;
BEGIN
OPEN retval FOR
select *
from ifsapp.butce_gerceklesme
WHERE budget_year = '2018'
AND USER_GROUP = birim_id ;
RETURN retval;
END BUTCE_REPORT_Fun;
and am trying to execute the function this way
SELECT * from table(IFSAPP.BUTCE_REPORT_FUN('3008'))
the line above generates this exception
ora-22905 cannot access rows from a non-nested table item
to keep in mind that ifsapp.butce_gerceklesme is a view (which I do not think that it matters).
So how I can solve this. any help is appreciated.
Actually, am trying to create a function that returns rows from the view above according to the parameters provided. so if I can achieve that in another way that would be better.

Ref Cursors are for use in program calls: they map to JDBC or ODBC ResultSet classes. They can't be used as an input to a table() call. Besides, there is no value in calling your function in SQL because you can simply execute the embedded query in SQL.
the main table is huge and the inner query assigned to USER_GROUP is selected every time
So maybe what you want is subquery factoring AKA the WITH clause?
with ug as (
select con2.CODE_PART_VALUE
from IFSAPP.ACCOUNTING_ATTRIBUTE_CON2 con2
where COMPANY = 'XYZ'
and ATTRIBUTE = 'ABC'
and CODE_PART = 'J'
and con2.ATTRIBUTE_VALUE=407
AND rownum = 1
)
select *
from ifsapp.butce_gerceklesme t
join ug on t.USER_GROUP = ug.CODE_PART_VALUE
WHERE t.budget_year = '2018'
Tuning queries on StackOverflow is a mug's game, because there are so many things which might be responsible for sub-optimal performance. But as a rule of thumb you should try to tune the whole query. Encapsulating a part of it in PL/SQL is unlikely to improve response times, and indeed may degrade them.

Related

how to compare one value against 2 values in Oracle

I want to compare a a value against 2 values without using OR or DECODE. The value I want to compare with two values is the one which I am getting as a return code of a function. If I use OR or DECODE then I have to call function twice and it gives performance hit. Currently I am coding as below
select *
from table1 t1, table2 t1
where t1.empid = t2.empid
and myfunction(t2.balance) = t1.total OR myfunction(t2.balance) = -1
Please suggest if there is a way to call function once and compare with 2 values.
To shorten your code you could use IN operator which acts like OR.
select *
from table1 t1
join table2 t1 on
t1.empid = t2.empid
and myfunction(t2.balance) in (t1.total, -1)
I've also replaced old-fashioned join syntax in where clause for JOIN keyword and you're advised to be using that in your future SQL journeys.
Good thing to know would be that even though you call the function twice, most modern databases would actually call it only once, so I wouldn't be that much concerned about it.

Oracle: function based index using dynamic values

I have one complex SQL queries. One of the simple part of the queries looks like:
Query 1:
SELECT *
FROM table1 t1, table2 t2
WHERE t1.number = t2.number
AND UPPER(t1.name) = UPPER(t2.name)
AND t1.prefix = p_in_prefix;
Query 2:
SELECT *
FROM table1 t1, table2 t2
WHERE t1.number = t2.number
AND UPPER(t1.name) = UPPER(p_in_prefix || t2.name)
AND t1.prefix = p_in_prefix;
I have function based index on table1 as (number, UPPER(name)). I have function based index on my table2 as (number, UPPER(NAME)). p_in_prefix is a input parameter (basically a number).
Because of these indexes my Query 1 runs efficiently. But Query 2 has a performance issue, as in Query 2, 't2.name' is prefixed with p_in_prefix.
I can not create function based index for Query 2 because p_in_prefix is a input parameter and I don't know while creating index, what values it might hold. How to resolve performace issue in this scenario? Any hint/idea would be appreciated. If you require more information, please let me know.
Thanks.
Use AND UPPER(t1.name) = UPPER(p_in_prefix) || UPPER(t2.name).
As you have a function based index as UPPER(NAME) of table2, you should have an operand with the same expression in the query in order to make use of the function based index.
Using UPPER(p_in_prefix || t2.name) will not use the function based index as this does not match the function expression UPPER(NAME). Note here that using UPPER(t2.name) does not cause any problems as t2 is just a column alias.
Along with this, you can also pass an optimizer hint in your query in order to instruct the optimizer to use the index.
For more information read "Oracle Database 11g SQL" by Jason Price.
Also read Oracle Docs here and here and for optimizer hints here.

Pagination with LINQ on Stored Procedures?

Is there a way where I can use something like the following code to paginate data without loading the whole data-set to the program?
var r = from c in entities.GetSearchData(null,"en",null,true) select c;
IPagedList<Models.SearchResult> results = r.ToPagedList<Models.SearchResult>(1, 10);
I'm trying to use a stored procedure with LINQ to get a paged result. (BTW the above code gives a "The result of a query cannot be enumerated more than once." error). Is it possible?
Can't test with Entity Framework at the moment, but the regular LINQ-to-SQL allows following statements:
var rpage1 = entities.GetSearchData(null,"en",null,true).Skip(0).Take(10)
var rpage2 = entities.GetSearchData(null,"en",null,true).Skip(10).Take(10)
var rlist = rpage1.ToList();
LINQ will generate a clause like
WHERE [t1].[ROW_NUMBER] BETWEEN #p0 + 1 AND #p0 + #p1
In my case the resulting query was (GetConstantsValues is a stored procedure):
SELECT [t1].[value] AS [Value]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[value]) AS [ROW_NUMBER], [t0].[value]
FROM [dbo].[GetConstantsValues](#p0) AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN #p1 + 1 AND #p1 + #p2
ORDER BY [t1].[ROW_NUMBER]
So only the relevant results are loaded into program.
I reckon, EF shouldn't differ much from it. May be wrong.
No need to go back to LINQ to SQL. There is a tweak that you can make. With entity framework, the result of a stored procedure is a collection of ObjectSet, hence the enumerations won't be allowed more than once, unless we convert it to a normal enumerable collection.
Simplest way to deal with such a case is as below,
var r = from c in entities.GetSearchData(null,"en",null,true) select c;
IPagedList<Models.SearchResult> results =
r.ToList().ToPagedList<Models.SearchResult>(1, 10);
Here r.ToList() makes the magic, and code would work without any hiccups!!
Note*: I know this is pretty old post, but thought of helping those who would come here looking for help!

Calling function in select vs calling temp table

Just looking if there is any way to have the following behaviuour.
Currently I'm doing
select * from table_1 t1 where function_call(t1.col1, t1.col2) <> 0;
The reason why I'm calling the function function_call is , The function has the table table_2 which I don't have access. The only way I can access is through one package.
Is there any way changing the above behaviour to, having the table information in the from clause instead of calling the function_call in where clause.
like ,
select * from table_1 t1, package_x.get_table_2() where t1.col1 = 1 and t1.col2 = 1 and t1.col3 = t2.col3
I agree that calling a function from the WHERE clause may result in slow performance as this will very likely result in a full table scan of TABLE_1, with the function being called once for every row in TABLE_1. I can think of several things your site can do:
Grant the necessary level of access to TABLE_1.
Create a view on TABLE_1 which restricts the data which can be seen, and grant appropriate access on the view, or
Live with the slow access times.
Share and enjoy.

How to loop in sql?

I dont want to use the "loop" related keyword, how can I implement loop with basic sql command in oracle ?
I have two table :
A:
ID, Color
B,
ID, AID, Type
I want to loop all records in B, and if ID = AID, then set the A.Color = B.Type
Thanks in advance !
Looping is, by definition, a procedural construct.
SQL is declarative: tell the database what you want done, not how to do it.
If you're absolutely convinced that you need to program such a thing, then write it in PL/SQL, Oracle's procedural language.
Bu I'm sure that it's possible to do what you want in SQL using an UPDATE with a WHERE clause.
Something like this (corrected per NullUserException):
UPDATE A SET A.Color = (SELECT B.Type FROM B WHERE A.ID = B.AID)
An alternate method:
MERGE INTO a
USING b
ON (b.aid = a.id)
WHEN MATCHED THEN UPDATE SET a.color = b.type;
You could just do:
UPDATE tablea a
SET a.color = (SELECT b.type
FROM tableb b
WHERE b.aid = a.id)
See this SQL script.
To do that you will have to write a stored procedure using PL/SQL. Here is the oracle page with some info and papers on the topic.
As others pointed out, you can probably solve your problem with a normal DML statement, without any looping involved. But to give you some basics on how to accomplish what you asked for in PL/SQL, here's an example...
DECLARE
CURSOR c IS
SELECT id, aid, type FROM b;
statement VARCHAR2(200);
BEGIN
FOR iterator IN c LOOP
IF iterator.id = iterator.aid THEN
statement := 'UPDATE a SET color = ' || iterator.type || 'WHERE id = ' || iterator.id;
EXECUTE IMMEDIATE statement;
END IF;
END LOOP;
END;
This anonymous PL/SQL block will iterate through each record in table b, and if b.id = b.aid, it will update table a and set a.color = b.type where a.id = b.id.
This seems to be what you were asking for. It's not exactly an efficient way to go about doing things, since you're firing off one DML statement per row in table b that has b.id=b.aid. But I wanted more to give this as a syntax example. This is just one way to iterate through a cursor by the way; you can also explicitly open cursors and fetch records, but it's easier this way if you don't need to do anything but iterate over the entire result set.

Resources