Which is better for returning resultset from an oracle database => Ref. Cursor vs Select sql statement - oracle

I have been googling for a while to find an alternative approach for returning a resultset rather than returning a ref cursor but failed to find it so. As i have done most of my development in sql server where we won't use cursors unless until it is necessary but i understand it differs from ref. cursor. But on top of that when we return a ref. cursor as an output from database it will become a connected architecture. So my dear Geeks can you answer/clear my confusions as mentioned below,
I want to understand which is the better way for returning a result set to our application (Ref. cursor or SELECT statement with all the joins or any other options)?
Is using ref. cursor is a connected /disconnected architecture?
Is using Select sql query is better for a disconnected approach?
Thanks in advance.

As usual, it depends on your needs.
Regarding connected /disconnected architecture it makes almost no difference. After your client application received the RefCursor and all rows are fetched (and preferably the cursor is closed) you can disconnect and reconnect from database the same way as using direct SELECT statement.
Consider following pseudo-code examples:
SELECT EMP_NAME, DEPT_NAME
FROM EMP
JOIN DEPT ON EMP_DEPT_ID = DEPT_ID
WHERE DEPT_ID = :d;
vs.
CREATE FUNCTION GetEmps(deptId IN NUMBER) RETURN SYS_REFCURSOR IS
res SYS_REFCURSOR;
BEGIN
OPEN res FOR
SELECT EMP_NAME, DEPT_NAME
FROM EMP
JOIN DEPT ON EMP_DEPT_ID = DEPT_ID
WHERE DEPT_ID = deptId;
RETURN res;
END;
My personal favorite is to prefer a RefCursors because:
With RefCursor client and server are more separated from each other, i.e. the client just has to know the function name and which attributes he receives (EMP_NAMEand DEPT_NAME), nothing else. He does not have to know the table names or any join condition. Developers of client and server can work more independently from each other.
With RefCursor you can implement fine-granularity security methods. You only have to do grant execute on GetEmps to ... and the client gets EMP_NAME and DEPT_NAME - no more, no less!
With direct SELECT you have to grant select on both tables, however then the client could also execute SELECT SALARY, EMP_NAME FROM EMP; for instance (unless you use the quite expensive VPD feature from Oracle). If you like you can log every single call of the function and add as many constraints as you like.
with RefCursor the client application (and not the server) can decide how many rows he like to fetch in order to optimize response times.

the basic difference is that when you are uncertain about the sql query you are going to execute at run time, then use ref cursor and you can use same ref cursor for different sql queries. for example
for query
select name,id,dob from table where id=:v_id;
here v_id is passed at run time, so we can use ref cursor. v_id varies at run time.
While the select statement is used in for each loop when we have small set of records. When we have large set of records we can use bulk collect with ref cursor and limit rows.

In Oracle, all DML statements are cursors. A cursor is simply a set of instructions used by the optimizer to get to the data.
In my Oracle-centric opinion, everything that is done in the database should be done in stored procedures, so that you have a central interface into the database - ie. if you had two applications updating/retrieving data to/from the same database, you'd only need one set of stored procs on the database, rather than replicating the logic twice in each application.
With that in mind, ref cursors are the way to go.
However, if you're not going down that route (boo! *{;-) ) there is little difference between a ref cursor and a straight select statement in terms of getting the data to the front end. How you call for the data will be different, of course, but it's the same thing to the database.
All a ref cursor does is basically hold a pointer to a cursor.

Related

How to know if a db-link is used somewhere in a DB

I would like to know if it exists an Oracle command to know if a DB-LINK (name: myBDLink) is used somewhere in a DB and how to display the objects (views,materialized views, procedures, functions, ...) which use it.
Could you please help me with that ?
Thanks for your help
Well, you could try to query various system views and see whether any of them contains a string you're looking for. As you want to check the whole database, you'll probably connect as a privileged user and check dba_ views; otherwise, all_ or user_ would do.
For example, to check procedures, functions, packages, ...:
select owner, name, type, line
from dba_source
where owner not in ('SYS', 'SYSTEM')
and lower(text) like '%mydblink%';
To check views, you'll need a function which will search through its LONG datatype column (as you can't use it directly in SQL):
create or replace function f_long(par_view in varchar2, par_String in varchar2)
return varchar2
is
l_text varchar2(32000);
begin
select text
into l_text
from dba_views
where owner not in ('SYS', 'SYSTEM')
and view_name = par_view;
return case when instr(lower(l_text), lower(par_string)) > 0 then 1
else 0
end;
end;
/
and then
select owner, view_name
from dba_views
where f_long(view_name, 'mydblink') = 1;
I excluded SYS and SYSTEM as they should not contain anything of users' stuff. Perhaps you'd want to exclude some more users.
To see some more (re)sources, query the dictionary, e.g.
select table_name, comments
from dictionary;
TABLE_NAME COMMENTS
------------------------------ --------------------------------------------------
USER_CONS_COLUMNS Information about accessible columns in constraint
definitions
ALL_CONS_COLUMNS Information about accessible columns in constraint
definitions
DBA_CONS_COLUMNS Information about accessible columns in constraint
definitions
<snip>
There is no complete answer. How would the database know of code that is outside of the database? It can't. So if you have a sql script, or some application that does not rely on stored procedures to do everything, the database will not know of them.
That said, for dependencies that are in stored procedures in the database, you can try this:
select *
from dba_dependencies
where referenced_link_name is not null
;
To add to the other (correct) answers that have been posted by #Littlefoot and #EdStevens, a quick-and-dirty analysis can also be made against the Automated Workload Repository (AWR).
The benefit of this approach is it will find usages of remote objects from SQL submitted to the database whether that SQL is in DBA_SOURCE or not (e.g., is embedded in an external application).
-- Find any objects referenced across a database link (sort of)
select object_node, object_name, count(distinct sql_id) sql_id_count
from dba_hist_sql_plan
where object_type = 'REMOTE'
group by object_node, object_name
order by object_node, object_name
;
The problem is that AWR data isn't 100% complete. First of all, it's not kept around forever, so a database link last used more than a month (or two months or however long your DBAs keep AWR data for) wouldn't be seen. Second of all, AWR only takes snapshots periodically, say every hour. So it's theoretically possible for a SQL to use a database link and then get aged out of the library cache before the next AWR snapshot.
I think the chance of missing something due to that last bit is small on the systems I work with. But, if you have poorly written applications (i.e., no bind variables) and limited shared pool space, it's something to worry about.

Dynamic Query Re-write or Evaluating the Query Before Executing Table Function

First, I want to make it clear that the question is not about the materialized views feature.
Suppose, I have a table function that returns a pre-defined set of columns.
When a function call is submitted as
SELECT col1, col2, col3
FROM TABLE(my_tfn(:p1))
WHERE col4 = 'X';
I can evaluate the parameter and choose what queries to execute.
I can either open one of the pre-defined cursors, or I can assemble my query dynamically.
What if instead of evaluating the parameter I want to evaluate the text of the requesting query?
For example, if my function returns 20 columns but the query is only requesting 4,
I can assign NULLs to remaining 16 clumns of the return type, and execute fewer joins.
Or I can push the filter down to my dynamic query.
Is there a way to make this happen?
More generally, is there a way to look at the requesting query before exuting the function?
There is no robust way to identify the SQL that called a PL/SQL object.
Below is a not-so-robust way to identify the calling SQL. I've used code like this before, but only in special circumstances where I knew that the PL/SQL would never run concurrently.
This seems like it should be so simple. The data dictionary tracks all sessions and running SQL. You can find the current session with sys_context('userenv', 'sid'), match that to GV$SESSION, and then get either SQL_ID and PREV_SQL_ID. But neither of those contain the calling SQL. There's even a CURRENT_SQL in SYS_CONTEXT, but it's only for fine-grained auditing.
Instead, the calling SQL must be found by a string search. Using a unique name for the PL/SQL object will help filter out unrelated statements. To prevent re-running for old statements, the SQL must be individually purged from the shared pool as soon as it is found. This could lead to race conditions so this approach will only work if it's never called concurrently.
--Create simple test type for function.
create or replace type clob_table is table of clob;
--Table function that returns the SQL that called it.
--This requires elevated privileges to run.
--To simplify the code, run this as SYS:
-- "grant execute on sys.dbms_shared_pool to your_user;"
--(If you don't want to do that, convert this to invoker's rights and use dynamic SQL.)
create or replace function my_tfn return clob_table is
v_my_type clob_table;
type string_table is table of varchar2(4000);
v_addresses string_table;
v_hash_values string_table;
begin
--Get calling SQL based on the SQL text.
select sql_fulltext, address, hash_value
bulk collect into v_my_type, v_addresses, v_hash_values
from gv$sql
--Make sure there is something unique in the query.
where sql_fulltext like '%my_tfn%'
--But don't include this query!
--(Normally creating a quine is a challenge, but in V$SQL it's more of
-- a challenge to avoid quines.)
and sql_fulltext not like '%quine%';
--Flush the SQL statements immediately, so they won't show up in next run.
for i in 1 .. v_addresses.count loop
sys.dbms_shared_pool.purge(v_addresses(i)||', '||v_hash_values(i), 'C');
end loop;
--Return the SQL statement(s).
return v_my_type;
end;
/
Now queries like these will return themselves, demonstrating that the PL/SQL code was reading the SQL that called it:
SELECT * FROM TABLE(my_tfn) where 1=1;
SELECT * FROM TABLE(my_tfn) where 2=2;
But even if you go through all this trouble - what are you going to do with the results? Parsing SQL is insanely difficult unless you can ensure that everyone always follows strict syntax rules.

ORACLE: Using CTEs (Common Table Expressions) with PL/SQL

First off, my background is in SQL Server. Using CTEs (Common Table Expressions) is a breeze and converting it to a stored procedure with variables doesn't require any changes to the structure of the SQL other than replacing entered values with variable names.
In Oracle PL/SQL however, it is a completely different matter. My CTEs work fine as straight SQL, but once I try to wrap them as PL/SQL I run into a host of issues. From my understanding, a SELECT now needs an INTO which will only hold the results of a single record. However, I am wanting the entire recordset of multiple values.
My apologies if I am missing the obvious here. I'm thinking that 99% of my problem is the paradigm shift I need to make.
Given the following example:
NOTE: I am greatly over simplifying the SQL here. I do know the below example can be done in a single SQL statement. The actual SQL is much more complex. It's the fundamentals I am looking for here.
WITH A as (SELECT * FROM EMPLOYEES WHERE DEPARTMENT = 200),
B as (SELECT * FROM A WHERE EMPLOYEE_START_DATE > date '2014-02-01'),
C as (SELECT * FROM B WHERE EMPLOYEE_TYPE = 'SALARY')
SELECT 'COUNTS' as Total,
(SELECT COUNT(*) FROM A) as 'DEPT_TOTAL',
(SELECT COUNT(*) FROM B) as 'NEW_EMPLOYEES',
(SELECT COUNT(*) FROM C) as 'NEW_SALARIED'
FROM A
WHERE rowcount = 1;
Now if I want to make this into PL/SQL with variables that are passed in or predefined at the top, it's not a simple matter of declaring the variables, popping values into them, and changing my hard-coded values into variables and running it. NOTE: I do know that I can simply change the hard-coded values to variables like :Department, :StartDate, and :Type, but again, I am oversimplifying the example.
There are three issues I am facing here that I am trying to wrap my head around:
1) What would be the best way to rewrite this using PL/SQL with declared variables? The CTEs now have to go INTO something. But then I am dealing with one row at a time as opposed to the entire table. So CTE 'A' is a single row at a time, and CTE B will only see the single row as opposed to all of the data results of A, etc. I do know that I will most likely have to use CURSORS to traverse the records, which somehow seems to over complicate this.
2) The output now has to use DBMS_OUTPUT. For multiple records, I will have to use a CURSOR with FETCH (or a FOR...LOOP). Yes?
3) Is there going to a big performance issue with this vs. straight SQL in regards to speed and resources used?
Thanks in advance and again, my apologies if I am missing something really obvious here!
First, this has nothing to do with CTEs. This behavior would be the same with a simple select * from table query. The difference is that with T-SQL, the query goes into an implicit cursor which is returned to the caller. When executing the SP from Management Studio this is convenient. The result set appears in the data window as if we had executed the query directly. But this is actually non-standard behavior. Oracle has the more standard behavior which might be stated as "the result set of any query that isn't directed into a cursor must be directed to variables." When directed into variables, then the query must return only one row.
To duplicate the behavior of T-SQL, you just have to explicitly declare and return the cursor. Then the calling code fetches from the cursor the entire result set but one row at a time. You don't get the convenience of Sql Developer or PL/SQL Developer diverting the result set to the data display window, but you can't have everything.
However, as we don't generally write SPs just to be called from the IDE, it is easier to work with Oracle's explicit cursors than SQL Server's implicit ones. Just google "oracle return ref cursor to caller" to get a whole lot of good material.
Simplest way is to wrap it into an implicit for loop
begin
for i in (select object_id, object_name
from user_objects
where rownum = 1) loop
-- Do something with the resultset
dbms_output.put_line (i.object_id || ' ' || i.object_name);
end loop;
end;
Single row query without the need to predefine the variables.

Alternate method to global temp tables for Oracle Stored Procedure

I have read and understand that Oracle uses only global temp tables unlike MS SQL which allows #temp tables. The situation that I have would call for me to create hundreds of Global temp tables in order to complete the DB conversion I am working on from MS SQL to Oracle. I want to know if there is another method out there, within a Oracle Stored Procedure, other than creating all of these tables which will have to be maintained in the DB.
Thank You
" Most of the time the only thing the temp tables are used within a
stored proc and then truncated at the end. We do constant upgrades to
our applications and having them somewhat comparable ensures that when
a change is made in one version that it can be easily merged to the
other."
T-SQL Temp tables are essentially memory structures. They provide benefits in MSSQL which are less obvious in Oracle, because of differences in the two RDBMS architectures. So if you were looking to migrate then you would be well advised to take an approach more fitted to Oracle.
However, you have a different situation, and obviously keeping the two code bases in sync will make your life easier.
The closest thing to temporary tables as you want to use them are PL/SQL collections; specifically, nested tables.
There are a couple of ways of declaring these. The first is to use a SQL template - a cursor - and define a nested table type based on it. The second is to declare a record type and then define a nested table on that. In either case, populate the collection variable with a bulk operation.
declare
-- approach #1 - use a cursor
cursor c1 is
select *
from t23;
type nt1 is table of c1%rowtype;
recs1 nt1;
-- approach #1a - use a cursor with an explicit projection
cursor c1a is
select id, col_d, col_2
from t23;
type nt1a is table of c1a%rowtype;
recs1 nt1a;
-- approach #2 - use a PL/SQL record
type r2 is record (
my_id number
, some_date date
, a_string varchar2(30)
);
type nt2 is table of r2;
recs2 nt2;
begin
select *
bulk collect into recs1
from t23;
select id, col_d, col_2
bulk collect into recs2
from t23;
end;
/
Using a cursor offers the advantage of automatically reflecting changes in the underlying table(s). Although the RECORD provides the advantage of stability in the face of changes in the underlying table(s). It just depends what you want :)
There's a whole chapter in the PL/SQL reference manual. Read it to find out more.

Populating a cursor with a rowtype variable

No amount of googling seems to find the answer to this one...
I'm trying to modify Oracle sproc that that currently pulling values out of some tables and moving them to other tables.
It has a ROWTYPE variable that is defined like this:
myRow my_tbl%ROWTYPE;
Right now, the sproc does some logic that populates the rowtype variable and then uses it to populate a table:
INSERT INTO MY_TBL
( col1,
col2,
col3,
-snip-
)
VALUES (
myRow.aValue,
myRow.aValue2,
myRow.aValu3,
-snip-
)
Instead of populating a table, I want to use the ROWTYPE to populate a cursor that is returned to a Web app. However, I can't find a way to do this ROWTYPE -> REF CURSOR conversion. Is this possible? If not, is there a way to manually populate a cursor with data drawn from various tables and using some complex logic? I'm using Oracle 10g.
Thanks!
The tricky part about this is that you are using a REF CURSOR, which is intended for a set of rows to return data for just a single row. I imagine you are just doing this because your web app understands ref cursors and how to get them from Oracle, but not object types. I am also guessing that for some reason you can't just write a single select statment to retrieve and manipulate the data as needed (this is the easiest way, so with more info we can possibly help you out to achieve it).
There are a few ways I can think of to do this, none of them very pretty, so hopefully someone else will chime in with a better idea.
1) Create the cursor by selecting your calculated variables from dual
DECLARE
refcur SYS_REFCURSOR;
myRow TBL%ROWTYPE;
BEGIN
myRow.aValue := 1;
myRow.aValue2 := 3;
myRow.aValue3 := 5;
OPEN refcur
FOR
select
myRow.aValue,
myRow.aValue2,
myRow.aValue3
from
dual;
CLOSE refcur;
END;
2) Create a pipelined function that returns a table of your rowtype, and create your cursor from a select from that function.
The select from dual would be something like
select myRow.aValue,
myRow.aValue2,
myRow.aValu3
from dual;
You should be able to declare a cursor for that.
There is a good writeup of REF CURSOR at http://psoug.org/reference/ref_cursors.html

Resources