Get the no. of rows returned from sys_refcursor - oracle

I am writing an Oracle stored procedure with an OUT parameter as SYS_REFCURSOR.
The procedure does something like below:
open ref_cursorA for select * from tableA
save the no. of records retrieved to another table.
return the ref_cursorA for generating an Excel report.
However, there is no way to know the number of rows retrieved before fetching from the cursor, but I really need to save the no. of rows retrieved in the s.p. What should I do in this scenario?

When you open a cursor, the query hasn't been executed yet. It will be executed when you fetch the result rows. And most likely the execution will be piecewise, i.e. a few rows at a time.
So the number of rows is only know when the last row has been fetched.
If you really need the number of rows in your stored procedure, you'll have to execute an additional query that just counts the number of rows before you open and return the cursor for the main query:
select count(*) into var from tableA
Save the the number of rows in a separate table
open ref_cursorA for select * from tableA
return cursorA
Note:.Depending on your transaction isolation level, the COUNT(*) query will return a slightly different count if data is inserted and deleted at the same time.

Related

how to save group by result to variable or another table in oracle?

I'm not familiar with stored procedure yet. For optimize a time consuming operation of select count(1). I want to save the result to another table or dictionary data structure.
and I can quickly fetch the value of a given keyword.
Such as:
select name, count(1)
from mytable where ... group by name
How to save pairs of name and count to another table or a dictionary data structure?

Improve DELETE query Oracle

I have a query to delete some records from a table, but take too much time.
The table is use it in a stored procedure to match another table.
Every time that the SP is executed the table is truncated and filled with 2 or 3 millions of records depending of the received parameters.
The table doesn't have any FK or constraints
The query to delete the records that I am using is:
DELETE FROM TABLE1
WHERE (fecha,hora_ini,origen,destino,tipo,valor,rowsm1) IN (
SELECT fecha_t,hora_t,origen_t,destino_t,tipo,valor,id_t
FROM TABLE2)
I try to decrease the time in execute the query creating an index based in the same columns of the query
CREATE INDEX smb1 ON table1 (fecha,hora_ini,origen,destino,tipo,valor,rowsm1);
And the query take more time to execute.
How can improve the performance of this "DELETE" query.
UPDATE
EXPLAIN PLAN OUTPUT
DELETE TABLE1
TABLE ACCESS TABLE1
TABLE ACCESS FULL TABLE1
TABLE ACCESS FULL TABLE2
TABLE ACCESS FULL TABLE2
The index you created looks like a quite big index:
CREATE INDEX smb1
ON table1 (fecha,hora_ini,origen,destino,tipo,valor,rowsm1);
Sure, this depends on the amount of data but generally I would rather look for one or two selective columns - if possible.
Don't forget, that the index data has to be read as well and if it doesn't help to speed up the query, you even loose performance.
This might for instance happen, if the table is very small, because the database reads data block by block (I think it was about 8K). A small table can be read in one step - no need to use an index here.
Or, if more or less all records are selected. In this case the table has to be read anyway.
If you want to speed up the query you should create the same index (with a good selectivity) on table2. This way the EXPLAIN PLAN will look somewhat lie this:
DELETE STATEMENT
DELETE
NESTED LOOPS SEMI
INDEX FULL SCAN
INDEX RANGE SCAN
You can switch off logging and delete the rows,
Here is an example, you can do it 2 ways,
1.) Physically chaning the table to Nologging
2.) Using Nologging hint in the delete statement.
1.) First approach
both testemp and testemp2 are same tables with same data while testemp takes over a minute , testemp2 takes only 1 second
SQL> delete from testemp;
14336 rows deleted.
Elapsed: 00:01:04.12
SQL>
SQL>
SQL> alter table testemp2 nologging;
Table altered.
Elapsed: 00:00:02.86
SQL>
SQL> delete from testemp2;
14336 rows deleted.
Elapsed: 00:00:01.26
SQL>
The table needs to be put back to logging only when we physically change the table using "Alter" command, if you are using as hint not required please see the example below
2.) Second approach
SQL> set timing on;
SQL> delete from testemp2;
14336 rows deleted.
Elapsed: 00:00:01.51
Deleting data after reinserting same data into table now with nologging;
SQL> delete /*+NOLOGGING*/ from testemp2;
14336 rows deleted.
Elapsed: 00:00:00.28
SQL> select logging from user_Tables where table_name='TESTEMP2';
LOG
---
YES

how to create a table at runtime in oracle sql developer

How can i create a temporary table at run time with as many columns as count from select query returns?
For example, at starting time it is not known how many items my select query will return as the user inputs it returns number of items under the search criteria that user has entered. So every item's information is to be stored in different columns therefore i need to create a table at run time.
Please suggest how it can be done?

Two DMLs based on Same Subquery

I need to cancel some orders, and then insert a row into another table, both based on the same subquery.
There is a very small chance that the subquery will return different rows between the time that the 1st and 2nd DMLs are issued.
But is there a proper way to do this such the orders updated are the same orders that are inserted into the cancellations table?
I am using Oracle and JDBC. Thanks.
update orders
set status = 'cancel'
where order_number in (select order_number from some_other_table_where...)
insert into order_cancellations
select order_number select order_number from some_other_table_where...
Here are five approaches that spring to mind:
(1) Put a trigger on the orders table so whenever the status is set to 'cancel', a row is inserted into order_cancellations.
(2) Use the returning clause in insert. Do the insert first and use this information for the update.
(3) Add a creation date to order_cancellations and do this insert first. Then update orders using the just-inserted rows
(4) Wrap the two statements in a transaction (this might require locking the other tables).
(5) Load the subquery data into a temporary table and use that table for both operations.
I also wonder if you could eliminate the need for the cancellations table just by having a cancellation_date column in the orders table.

Number of Records in Insert Statement (Oracle)

I'd like to report on the number of records inserted in an Oracle insert statement. I'm inserting from a statement, so I could run my select twice and a count, but I'd rather keep it all in a single statement. Is there a way?
Doing an INSERT in PL/SQL SQL%ROWCOUNT gives the number of inserted rows.
Doing an INSERT in C# cmd.ExecuteNonQuery() returns the number of inserted rows.

Resources