Why using cursors in PL/SQl ORACLE? - sql

I'm a beginner at PL/SQL, and during studying the course I saw CURSOR
and I want to know why we should use it, and when?
thank you very much

When you do a SELECT and it returns more than one row you can't save the rows in a variable, so you'll have to use a CURSOR. If you are familiar with programming a CURSOR is something like an Array.
So if you do a SELECT and save the results in a variable like in the code:
SELECT id INTO v_id FROM table;
and if more than one row is returned, you cant save the rows in the variable v_id, and a TOO_MANY_ROWS Exception will be thrown.
Reference: http://www.oracle.com/technetwork/issue-archive/2013/13-mar/o23plsql-1906474.html

Also, if you've seen Oracle's FOR ... IN (SELECT ...) ... LOOP ... END LOOP statement, that's using an implicit cursor.
The reason to use the explicit cursor method is that you can do more things with the cursor, such as BULK COLLECT which can greatly improve your processing performance in many, but not all, situations. That greater control (beyond just doing BULK COLLECT) is helpful as you develop more-elaborate processes.
Good luck on your journey into Oracle. I've been using it for 14 years and am a big fan.

Related

SQL - Extremely human readable, but I don't understand the concepts behind it

I seem to approach thinking about sql the wrong way. I am always writing things that do not work.
For example I need a variable. So i think:
DECLARE #CNT AS INT
SET #CNT = COUNT(DISTINCT database.schema.table.column)
Why doesn't this work...? I am using a fully qualified reference here, so the value I want should be clear.
DECLARE #CNT AS INT
SET #CNT = (SELECT COUNT(DISTINCT database.schema.table.column) FROM column)
This works... but why do I have to use select?
Does everything have to be prefaced with one of the DDL or DML statements?
Secondly:
I can't debug line by line because a sql statement is treated all as one step. The only way I can debug is if I select the innermost sub-query and run that, then include next outer sub query and run that, and so on and so forth.
Is there a locals window?
I've heard about set-based thinking rather than iterative thinking, I guess I am still iterative even for functional languages... the iteration is just from innermost parentheses to outermost parentheses, and applied to the whole set. but even here I run into trouble because I don't know which value in the set causes the error.
Sorry if this seems scatterbrained... I guess that just kinda reflects how I feel about it. I don't know how to architect a big stored procedure from lots of little components......Like in vba I can just call another sub-routine and make sure the variables I need are global.
tldr: Need the conceptual grounding / knowing what actually happens when I type something and hit F5
On Question #1, You need select because that's how SQL works. You've given it a name, but haven't told it what to do with that name (select it, update it, delete it?) Just saying the column name is not grammatically correct.
On #2, Yes, SQL is declarative, you're not telling it what to do, you're telling it what to return. It will retrieve the data in the order that is most efficient at that particular moment in time, Normally your sub-query will be the last thing to run, not the first.
Yes, you have to use SELECT in-order to fetch that data first and then assign it to variable. You can also do it like
DECLARE #CNT AS INT
SELECT #CNT = COUNT(DISTINCT `column`) FROM database.schema.table

Firebird Cursors - Why would you use one

In the documentation here, the following code example is given for using a cursor:
execute block
returns (
relation char(31),
sysflag int)
as
declare cur cursor for
(select rdb$relation_name, rdb$system_flag from rdb$relations);
begin
open cur;
while (1=1) do
begin
fetch cur into relation, sysflag;
if (row_count = 0) then leave;
suspend;
end
close cur;
end
But this can also be done as follows:
execute block
returns (
relation char(31),
sysflag int)
as
begin
for select rdb$relation_name, rdb$system_flag
from rdb$relations
into relation, sysflag
do begin
suspend;
end
end
So why would I want to use one? Ultimately the above example doesn't even need execlute block as it's just a simple select statement. So I suppose the example is just too simple to showcase a benefit of this.
The documentation you link to (and its newer 2.5 counterpart) already includes most of the reasons why you would (or would not) use a cursor (emphasis mine):
If the cursor is needed only to walk the result set, it is nearly always easier and less error-prone to use a FOR SELECT statement with the AS CURSOR clause. Declared cursors must be explicitly opened, used to fetch data and closed. The context variable ROW_COUNT has to be checked after each fetch and, if its value is zero, the loop has to be terminated. A FOR SELECT statement checks it automatically.
Nevertheless, declared cursors provide a high level of control over sequential events and allow several cursors to be managed in parallel.
So in short, you should usually use FOR SELECT, except when you need access to multiple cursors at the same time, or maybe need some more complicated logic than just a simple loop. It also makes it possible to reuse the same cursor definition in multiple parts of your code (although that might indicate you need to break up your code in multiple stored procedures).
Presence of a tool does not mean that it should be used for everything.
As an aside, a FOR SELECT is also a cursor, except you don't have explicit control over it (it hides most of the ugliness ;)).
Another situation one might use cursors is when it's needed to update retrieved rows, and finding or repositioning (determining the exact WHERE clause) the rows could be an issue. In this case, you can open cursors with FOR UPDATE clause, and update (or delete) rows using WHERE CURRENT OF clause.

Measure cost of SELECT statement in PL/SQL

I'm trying to measure how much does a select cost. Normally I would do it simply by getting the value of consistent gets before executing the statement and after, however, I'd like to wrap it in PL/SQL so that it's more generic. The problem I'm facing however, is how can I simply run a select without actually storing the result?
One of the ideas I had was to wrap it in a for loop like so
select value into getsBefore from v$sesstat ...
for dummy in (select name from my_table where city = 'XYZ') loop
i := i;
end loop;
select value into getsAfter from v$sesstat ...
But this doesn't seem like a correct approach.
I guess that I could simplify my question to - how can I SELECT something INTO <nothing>?
Any ideas or hints on how to accomplish this?
Thanks
Try : SELECT * bulk collect INTO [variable]
See this as a reference SELECT INTO Statement
Since the counters in V$SESSSTAT are absolute since a session is started there is no other way than to store a snapshot before an action and then subtract the snapshot from new one after the action is executed.
One of Tom Kyte's most used scripts is RUNSTATS meant to compare two actions performing the same thing to see which implementation is better.
You can find of the versions with description at http://betteratoracle.com/posts/12-runstats

SQL Alternative to For Loop

I'm working with SQL in Access. I'm not much of a programmer, but I'm familiar with using VBA as well as SQL basics.
What I'm trying to accomplish is the equivalent in SQL of a for loop used in Visual Basic. I know this isn't "technically" possible in SQL and may not be the best method so I'm looking for advice. I know it can be accomplished for i=1,2,3, etc. by using unions and repeating the query for each value. This is inefficient and easily gets too complex to be evaluated.
Basically what I need is a method to query for i=1 then repeat and again output data for i=2 and so on. Using group by i is not an option because there are several subqueries involved as well.
Thanks in advance!
OK what you need to accomplish is not really clear, I recommend posting your table structure and what you need to retrieve.
However, what you want "seems" to be doable using an IN statement.
select
*
from
whatever
where id IN (1,2,3)
Without a lot of context, we can't provide a better answer, but you can accomplish something of a FOR loop in sql.
declare #ctr integer
set #ctr = 1
while #ctr < 1000
begin
--Do your logic
select #ctr = #ctr + 1
end
But this isn't a very efficient use of SQL. You should be able to write what you need without iterating over it. Think in SETS and you will get along better with your RDBMS.

Difference between implicit and explicit cursors in Oracle

I want to know the difference between these two statements. Is one 'better' than the other ?
DECLARE
myvar varchar2(50);
BEGIN
SELECT fieldone into myvar FROM tbl_one WHERE id = 1;
END;
AND
DECLARE
CURSOR L1 IS
SELECT fieldone FROM tbl_one WHERE id = 1;
BEGIN
OPEN L1;
FETCH L1 INTO myvar;
CLOSE L1;
END;
The first will raise an exception if there are no rows returned or if more than one row is returned. If you don't handle the exception, that gets thrown back to the calling routine or client software. This is known as an implicit cursor.
The second would fail silently. If no rows are returned, then myvar will have a null value (though its preferable if you assume it is undefined). If more than one row would be returned, then only the value from the first row is stored. Without an ORDER BY, which value is 'first' is undefined. This is known as an explicit cursor.
So the question is really, what do YOU want to happen in the event of a no data found or too many rows situation. If you are certain that will never happen, or don't know how to handle it, then go with option 1.
If you do expect a no data found situation only, then go with the implicit cursor but add an exception handler.
If you expect multiple rows, then either the implicit cursor with an exception handler, or a BULK SELECT or CURSOR LOOP if you actually need to process the multiple rows.
If you are going to select multiple fields, it can be useful to define an explicit cursor and use a %TYPE declaration to declare all the necessary variables.
From a performance point of view, there's no difference.
From a maintainablilty point of view, some people like their SELECT 'in-line' with their code (so prefer the implicit cursor). I prefer mine 'out of the way', especially if there is a big column list, so I like explicit cursors.
I don't know what question you're asking, but here goes.
Should you use PL/SQL like this?
declare
myvar varchar2(50);
begin
select fieldone
into myvar
from tbl_one;
end;
/
Well, you can if and only if you know that the select statement can return exactly one row; alternatively, you need error handling for the TOO_MANY_ROWS and NO_DATA_FOUND exceptions which would be raised otherwise.
When using explicit cursors (i.e., the CURSOR keyword), there are several operations against it which control its behavior.
declare
myvar varchar2(50);
CURSOR L1 IS
SELECT fieldone FROM tbl_one ;
begin
OPEN L1;
FETCH L1 into myvar;
CLOSE L1;
end;
/
CURSOR L1... is the cursor's declaration. It's nothing more than binding the static SQL statement, and all the PL/SQL engine does is check that the SQL is syntactically and contextually valid - are there missing clauses? Can this user SELECT from this table?
OPEN L1 opens the cursor, establishing the exact point in the history of the system which the results will reflect. Any subsequent FETCHes against that cursor will reflect the data as of that precise point.
FETCH L1... actually returns the first/next row of that result set, whatever it is, into the variables you've specified. It could be a record declared, or it could be list of variables.
CLOSE L1... frees any resources your cursor has open; for example, insert/update/delete operations that affect the records generate undo that your user session has a declared read interest in, so that undo can't be freed or reused until you've closed your cursor.
Generally, the less code you write, the more robust your solution is. This is why we don't favor assembler level languages anymore.
This idea applied to cursors, has been eloquently criticized by Joe Celko in one of his books:
Cursor is a way to transform query result set into a stream that can be processed in a host 3GL language. Cursors are not compatible between different RDBMS vendors, and generally work slower than declarative SQL queries. Then, why bother? Mainly because of ignorance of database fundamentals and old habits. Here is detailed analogy:
ALLOCATE = turn tape recorder power on, assign channel
DECLARE CURSOR FOR ... = mount the tape and declare file
OPEN = open the file
FETCH INTO = read in the program records one by one, move the head
CLOSE = close file, dismount tape from the recorder
DEALLOCATE = free tape recorder channel, power off
This quote reads especially funny in Russian translation edition of his "SQL Programming Style" where the "tape recorder" sounds like "audio tape deck". And the suggestion that somebody still operates a tape deck in the world infested by iPods, iPhones and alike is hilarious.
Then, Joe goes through an anecdotal case of a newbie programmer who arranged three cursors to work together to iterate through master-detail data that have chosen conforming records and performed update. Eventually 250 lines of code were thrown away in favor of a single SQL update statement.
Personally, I'd got for the first version whenever possible. Keep it simple. One statement instead of five, more readable.
In Oracle (unlike SQL Server) all SELECTs are cursors - all declaring a cursor does is get you a handle that you can then use to manipulate it. The execution plan will be identical in both of your cases.