All of the examples that I found of FETCH NEXT fetch INTO pre-defined variables. So:
DECLARE #Whatever Int
FETCH NEXT FROM my_cursor INTO #Whatever
Is there a way to FETCH or otherwise deal with a cursor so that the entire row is accessible (like in a table) without having to define each variable? So perhaps I can fetch into something other than a scalar? Or can I query the cursor directly?
You can't. You can UPDATE or DELETE from a cursor using WHERE CURRENT OF but if you're selecting it needs to go into variables
Is it possible to repace the cursor with a table variable? You'd be able to deal with the full row and would probably increase performance.
Post more of what you're trying to do and maybe we can help more...
Related
I've a question and I hope that I find someone who can help Me:
I want to calculate all the rows returned by the cursor into the 'IF' (whitout using a counter because I want to know the number of rows in one time before begin the treatments.
TO EXPLAIN MORE: I have a table that contains measurements, and I want to know if the test (code inside my IF) returns a lot of mesurements or Not. If it returns One I want to send a message, else I send a message that contains a lot of mesurements .
Thank you
I think this will depend on what you mean by 'a lot' of measurements. nilsman's approach will get you the answer you want. However you will have to execute the cursor again if you actually want the data.
I can think of two approaches that might give you the answer you want
open your cursor using BULK COLLECT. You can then use the COUNT method on the collection you fetched into. However normally we would limit the number of rows collected at any one time to a few hundred at the most. If your definition of 'a lot' is bigger than a few hundred then this approach may not be efficient
use the analytic function COUNT(*) OVER () to return the count of all records in-line with each row of the query. This means after the first fetch you'll know the size of the entire result set
Seems like you need to use SQL%ROWCOUNT.
Look at https://docs.oracle.com/cloud/latest/db112/LNPLS/static.htm#CIHJJJDG for more info.
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.
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.
I know a set based solution is ideal and generally superior to a cursor. So please. Save your and mine time by abstaining from answers "don't use cursor, use set based ops". I am asking this because my Googling has not given any answers and the knowledge probably comes from experience:
1) FETCH NEXT FROM vs FETCH FROM When i open up a cursor (fast_forward/static), is there a difference between using 'fetch next from' and 'fetch next' inside the while loop? In performance, order of records accessed etc.
2) ROW_NUMBER + SELECT/WHILE vs STATIC CURSOR As I understand it, a static cursor creates a temp table with the data selected and goes over this temp table. So, is there any reason to use select row_number() ..., ... from ... into ... and iterate over it with a index variable and select * from #tmp table where RowNumber = #IndexVar?
3) FAST_FORWARD - can it break down? if i have a fast_forward local cursor, and inside this cursor insert/update operations are performed on tables the cursor selects from, are there any issues? (possible cycles etc?)
4) PLAN FORCING Is there a way to force a fast_forward cursor to use static/dynamic plan?
Thank you very much for your answers
PS: For those of you really curious, yes, the problem could be rewritten into a set-based approach, but due to some decisions from higher-up, new rows created in the primary table have to be created/inserted using a stored procedure.
is there a difference between using 'fetch next from' and 'fetch next' inside the while loop
No - NEXT is the default if no option is specified
So, is there any reason to use select row_number() ..., ... from ... into ... and iterate over it with a index variable and select * from #tmp table where RowNumber = #IndexVar?
I would presume that a static cursor has optimizations that would perform faster that you creating a temp table and searching for a specific row in each iteration, but I'd have to try it.
if i have a fast_forward local cursor, and inside this cursor insert/update operations are performed on tables the cursor selects from, are there any issues? (possible cycles etc?)
I'm not sure what you mean by "cycles" - if the underlying data changes the cursor will change as well (unless you declared it as STATIC)
Is there a way to force a fast_forward cursor to use static/dynamic plan?
I've never tried it, but you could try using OPTION( USE PLAN ...) in your SELECT when you define the cursor. I can't think of a reason why it wouldn't work.
i am getting mad about this and google is clueless
Google just reports what people put on the internet... Why are you mad? What problem are you trying to solve?
NEXT is the default fetch option, so FETCH = FETCH NEXT
Static/Dynamic refers to whether or not changes made by the cursor result set are reflected, ie if you insert new values into the static cursor result set it will not loop through those, it's whatever results are there when the cursor is declared/opened, and that's it, I believe your understanding is correct.
I'm not sure.
I'm not sure what you mean here, you can indicate dynamic or static when you declare your cursor.
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.