I have a cursor that iterates a table. Each row is inserted into a type that is equal to the cursor row.
CURSOR lc_lines
IS
SELECT tlc1, tlc2, tlc3
FROM table_x
ORDER BY tlc1;
TYPE table_lines IS TABLE OF lc_lines%ROWTYPE
INDEX BY PLS_INTEGER;
i_table_lines table_lines;
I needed to dynamically access the columns in the type. Something like this:
LOOP
FETCH lc_lines
BULK COLLECT INTO i_table_lines
LIMIT p_i_limit;
--e ai vamos nos :)
FOR i_idx IN 1 .. i_table_lines.COUNT
LOOP
varx := i_table_lines (i_idx).tlc||'2';
Is this possible?
Thanks in advance
You should be able to use DBMS_SQL routines to do this ... it's there to assist with complex, dynamic SQL/cursors, etc.
Try reading over the documentation here:
http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/dynamic.htm#LNPLS00001
You basically setup your cursor, your binds, your columns, etc.
then you can start accessing them without necessarily knowing how many columns you have in the first place.
[edit] I linked to the oracle 11 page, however, that feature's pretty much same between Oracle 10 and 11 .. here's the 10g doc if you need :
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm#i996963
[/edit]
Related
I have two tables in my database. Each table is having 2000 records. As I have a large number of records I would like to write the most optimal code for retrieving records. USER_DETAILS table is:
+---------+-----------+-----------+
| user_id | user_name | join_date |
+---------+-----------+-----------+
The second table which is refering USER_DETAILS table is:
+---------+-----------+-----------+
| user_id | fav_color | fav_dish |
+---------+-----------+-----------+
I have two approaches first one:
SELECT UD.*,FAV.FAV_COLOR, FAV.FAV_DISH FROM USER_DETAILS UD, FAV_DETAILS FAV
WHERE UD.USER_ID = FAV.USER_ID;
Second approach is writing a PL/SQL procedure which is:
DECLARE
CURSOR C1(X NUMBER) IS SELECT * FROM USER_DETAILS WHERE USER_ID = X;
CURSOR C2 IS SELECT * FROM USER_FAV;
Y NUMBER := &USER_ID;
BEGIN
FOR C IN C1(Y)
LOOP
DBMS_OUTPUT.PUT_LINE('USER DETAILS');
DBMS_OUTPUT.PUT_LINE('----------------');
FOR D IN C2
LOOP
IF C.DEPTNO = D.DEPTNO THEN
DBMS_OUTPUT.PUT_LINE(RPAD(C.USER_ID,10)||RPAD(C.USER_NAME,10)||RPAD(D.FAV_COLOR,10));
END IF;
END LOOP;
END LOOP;
END;
Which code will give better performance and why? I want to get the complete details of a user.
If I am using cursor will I get all the records form the server to the SGA? I will use this database in a JSP page which will be accessed by mobile devices only.
As internet in mobile device is very slow of my target users (around 10KB) hence I am concerned about bandwidth. In my point of view I find that performing a join will do a Cartesian product and check for matching result which will take one condition out of 1000*1000 conditions where as the checking conditions in PL/SQL block is only 1000 + 1000. It reduces the number of conditions. But as per my knowledge cursor will create a shadow page in client memory and it will create the table. This means it will fetch all the data form the server and store in client. Am I correct at this point?
You can read here Tom Kyte's mantra:
You should do it in a single SQL statement if at all possible.
If you cannot do it in a single SQL Statement, then do it in PL/SQL.
If you cannot do it in PL/SQL, try a Java Stored Procedure.
If you cannot do it in Java, do it in a C external procedure.
If you cannot do it in a C external routine, you might want to seriously think about why it is you need to do it…
Basically by using a plsql stored procedure you move from sql engine to plsql engine back and forward. More then that, if you have the right indexes and you build your query right, the sql optimizer will probably make things faster than you.
Here is another good AskTom post
Generally using a single select statement will have better performance
by a single select you will hit RDBMS Sql engine once and RDMS will use internal procedures (indexes, cashed queries ...) boosting performance.
In programming way (ignoring internal RDMS functionality)
in the first query you are doing a search with order of efficiency O(n)
in second plsql statement, by using nested loops you are doing a search with order of efficiency O(n^2)
search order of efficiency
Use cursor when you want a pointer on each row of your rsult in order to perform further actions. If you just need a select statement, just do a select statment. Cursor is will be an overkill. Keep it simple.
In a number of places in my applications, I need to display data as CSV.
For this, I usually loop through a cursor and build the CSV.
for j in c_get_mydata loop
v_CSV := v_CSV || ', ' || j.column_value;
end loop;
How can I write a re-usable function that could accept a query and return a CSV string? Do you recommend having this as a separate function or is it better to process each query like above? If you recommend having it as a separate function, do you recommend that the function take the string of the query or the resultant cursor as input?
EDIT:
Clarification: I want to display a single column of data as one row, separated by commas.
E.g.: Tom, Dick, Harry, Sally
I'm not looking to display multi-column data on multiple rows as:
Tom, 18, London
Dick, 22, New York
Harry, 16, San Fransisco
Sally, 18, Paris
EDIT 2:
I found out about the collect function:
select collect(employee_name)
from employees
This returns me a dataset, but how can I convert it into a string?
The simplest option would generally by to use the DBMS_SQL package. Tom Kyte has a good example with his dump_csv procedure. Of course, you probably want to write the results to a CLOB rather than writing it to a file using utl_file but that's a relatively easy tweak to make.
Old question and already correctly answered I know, but as this is one of the top Google hits for "oracle cursor to csv" and I've just written something to do this, I thought I'd post a new answer.
From Oracle 11.2 onwards DBMS_SQL can handle a normal ref cursor rather than just a string as in Tom Kyte's 2000 solution. You ingest it into DBMS_SQL using
l_cursor_id := dbms_sql.to_cursor_number(your_refcursor);
(l_cursor_id will then contain a meaningless generated number that DBMS_SQL uses to track its corresponding internal values.)
Since the ref cursor was already opened and parsed, you skip those steps and call
dbms_sql.describe_columns(l_cursor_id, l_col_count, l_cursor_columns);
where l_cursor_columns (an OUT parameter that DBMS_SQL populates for you) is a dbms_sql.desc_tab, which is an array of column definitions populated with an entry for each column in the query and containing the column name, datatype etc, and l_col_count somewhat redundantly contains the same value as l_cursor_columns.count. You then need to loop through this array calling dbms_sql.define_column to tell DBMS_SQL to handle each one using the datatype it just told you, a rather verbose step I can never quite see the point of. (It does allow you to treat all '%CHAR%' types as varchar2 etc so I guess it allows some flexibility.)
Then it's just a matter of calling dbms_sql.fetch_rows in a loop and processing the results. I put this in a pipelined table function which accepts a ref cursor argument, so you get something like this:
select column_value
from table(csv.report(cursor(
select * from dept -- << Use any query here
)));
COLUMN_VALUE
----------------------------------------------
10,ACCOUNTING,NEW YORK
20,RESEARCH,DALLAS
30,SALES,CHICAGO
40,OPERATIONS,BOSTON
4 rows selected.
Full writeup and code here:
www.williamrobertson.net/documents/refcursor-to-csv.shtml
I have a stored procedure in a Oracle database.
In this stored procedure I have defined a cursor.
I iterate through the result set using:
FOR item IN cursor_name LOOP
END LOOP;
How many times does the query execute ? Is there a way for me to know ? and also is this the best approach, or should I iterate in a different way ?
Thanks.
The query in the cursor cursor_name is executed only once. How many times you fetch from that cursor depends. Each fetch means a context switch. From Oracle version 10 onwards, if you set parameter PLSQL_OPTIMIZE_LEVEL to its default of 2 or higher, an optimization kicks in and you will fetch 100 rows at a time. Without this, you would fetch each row separately. Which would harm performance considerably when fetching a lot of rows.
Also beware that you don't put SQL statements inside the loop. When you do that, you will obviously execute those statements as many times as there are rows fetched from your cursor.
Regards,
Rob.
There have been a couple of hints that seem to have gotten me close here, but with some unique issues, I'm hoping this question is distinguishing enough to merit its own posting.
For starters here's what I have. I have an Oracle procedure that returns a standard REF CURSOR, and this REF CURSOR is passed back to my application. The REF CURSOR is a list of lookup IDs.
I then want to take this list and bring it to another data store and use it in a select statement. It will absolutely be possible to accomplish this by looping through the REF CURSOR, but I'm hoping to avoid that. I would much rather be able to write a SELECT...WHERE lookup_id IN result_ref_cursor OR SELECT...WHERE EXISTS...
First is this possible or should I just try a less than elegant solution? If it is possible, any hints as to where I should get started looking?
I'm relatively new to Oracle, but fairly experienced in RDBMs in general, so feel free to just through some links at me and I can study up. Much appreciated
Why kurosch didn't put his response as an "answer" I'll have no idea.
So, what you do is define a SQL type which describes one row of the output of the ref cursor, and also a SQL type which is a table of the previous. Then, you'll create a pipelined function which returns the rows returned by the ref cursor. This function can then be used in a standard SQL. I'm borrowing from Ask Tom on this one.
create or replace type myLookupId as object ( id int)
/
create or replace type myLookupIdTable as table of myLookupId
/
create or replace function f return myLookupIdTable PIPELINED is
l_data myLookupId;
l_id number;
p_cursor SYS_REFCURSOR;
begin
p_cursor := function_returning_ref_cursor();
loop
fetch p_cursor into l_id;
exit when p_cursor%notfound;
l_data := myLookupId( l_id );
pipe row (l_data);
end loop;
return;
end;
/
And now a sample query...
SELECT *
FROM SOME_TABLE
WHERE lookup_id in (SELECT ID FROM table(f));
Sorry if the code isn't exactly right, I don't have the DB to test right now.
There are several directions you could go with this, but I did a search on the specific solution you want and it seems like no-one has done it often enough to show up there. What you can do is search the oracle metalink - that is usually really good at finding obscure answers. (Though you do need a service agreement - just found out that mine expired :( )
Other possible solutions:
Create a link between the data stores so that you can do the select in the plsql directly
Create a function in Java that loops through it for you to create the string for the query. This will look a little more pretty at least.
Otherwise, REF CURSOR's need to go back and forth - I don't know how you can pipe the results of the REF CURSOR in one connection to the query in another without looping through it.
Is there an operator in Oracle that fetch a column of a row in a result set without having to specify the column's name. I want something like:
for row in (select * from table1)
loop
for col in row
loop
// do stuff with col
end loop;
end loop;
Thank you.
There is no built in function for this. You will have to use DBMS_SQL package in order to use dynamic SQL : http://docstore.mik.ua/orelly/oracle/bipack/ch02_02.htm
In static SQL, no.
If you were using dynamic SQL (via DBMS_SQL), you could describe the statement and iterate over the columns. But if the query itself is not dynamic, it would almost certainly increase the complexity of the code and decrease the maintainability if you were to move toward using DBMS_SQL rather than simply coding the column names that you're interested in.