Get the Affected Row from PL-SQL - oracle

I am using ODP.Net and run the PL/SQL Command to merge the table in the Oracle 10G database.
My command is as follow:
MERGE INTO TestTable t
USING (SELECT 2911 AS AR_ID FROM dual) s
ON (t.AR_ID = s.AR_ID)
WHEN MATCHED THEN
UPDATE SET t.AR_VIUAL_IMPAIRMENT = 1
WHEN NOT MATCHED THEN
INSERT (AR_S_REF)
VALUES ('abcdef');
SELECT sql%ROWCOUNT FROM dual;
The Merge command runs successfully and update/insert as I want. The problem is I want to know how many records are updated.
When I run the above statement, "ORA-00911: invalid character error".
Please advise me how I could get the affected rows back. Thanks million.

You're mixing up a few things: a MERGE statement is a plain SQL command while PL/SQL code is always delimited by BEGIN/END (and optional DECLARE). Furthermore, SQL%ROWCOUNT is a PL/SQL variable that cannot occur outside of PL/SQL.
And I don't quite understand whether you ran the MERGE and the SELECT statement with two separate or a common ODP.NET call.
Anyway, the solution is straightfowrad with ODP.NET: Execute the MERGE command with OracleCommand.ExecuteNonQuery(). This method returns the number of affected rows.

One thing you could do is put your code in a PLSQL function that returns %ROWCOUNT.
Then call this function from ODP.net setting the command type to stored procedure and using the ExecuteLiteral method which is going to return you the row count as an object instance you can cast as an int.

It is not possible to return just the "updated" row count.
(as already mentioned the row count is the number of affected (inserted and updated) rows)
there is a good discusion on ask tom: http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:122741200346595110

Related

Oracle 19: Why IN gets converted to Exist in explain plan and any suggestions around it

Please see image below:
As per that the IN query got converted to Exists in explain plan. Any reason for that? does it mean Oracle automatically converts IN to Exists?
Also any suggestion to reduce the cost? this statement is a part of a SP and it receives ~ separated string ('123') for example (63278~63282~63285~63288~63291~63296~63299~63302~63305~63308~63311~63314~63319~63322~63325~63329~63332~63253~63256~63260~63264~63267~63272~63275~63279~63283~63286~63289~63292~63297~63300~63303~63306~63309~63312~63315~63320~63323~63326~63330~63333~63269~63258~63277~63294~63317~63262~63270~63281~63295~63318~63328~63254~63257~63261~63265~63268~63273~63276~63280~63284~63287~63290~63293~63298~63301~63304~63307~63310~63313~63316~63321~63324~63327~63331~63334) in query. It takes around 10 to 15 mins to execute.
How can we generate explain plan for entire stored proc? We are using Oracle 19.
Thank you in advance.
IN clause retrieves all records which match with the given set of values. It acts as multiple OR conditions. IN clause scans all rows fetched from the inner query.
But, EXISTS is a Boolean operator that returns either True or False. Its used in combination to a sub-query. If the subquery returns any row, it returns True else False. If the result of data large inside the IN clause, then not recommended using IN. For getting high performance most time uses EXISTS vs IN. For that Oracle and PostgreSQL converts your IN to EXISTS
Since you are doing the job in a PL/SQL procedure you could create (out of the procedure) a GLOBAL TEMPORARY TABLE with DELETE ON COMMIT, in the procedure you INSERT in this table the result of the sub select with the CONNECT BY, then your replace the SELECT ... CONNECT BY by a SELECT in the temporary table. The temp table will be emptied at the end of the procedure and this method is session safe. And you have benefit of the index and probably a better plan. You could also compare the UPDATE with 2 ones: splitting the OR condition on 2 statements.

Problems inserting data into Oracle table with sequence column via SSIS

I am doing data insert into a table in Oracle which is having a sequence set to it in one of the columns say Id column. I would like to know how to do data loads into such tables.
I followed the below link -
It's possible to use OleDbConnections with the Script Component?
and tried to create a function to get the .nextval from the Oracle table but I am getting the following error -
Error while trying to retrieve text for error ORA-01019
I realized that manually setting the value via the package i.e. by using the Script task to enumerate the values but is not incrementing the sequence and that is causing the problem. How do we deal with it? Any links that can help me solve it?
I am using SSIS-2014 but I am not able to tag it as I don't due to paucity of reputation points.
I created a workaround to cater to this problem. I have created staging tables of the destination without the column that takes the Sequence Id. After the data gets inserted, I am then calling SQL statement to get the data into the main tables from staging table and using the .nextval function. Finally truncating/dropping the table depending on the need. It would still be interesting to know how this same thing can be handled via script rather having this workaround.
For instance something like below -
insert into table_main
select table_main_sequence_name.nextval
,*
from (
select *
from table_stg
)
ORA-01019 may be related to fact you have multiple Oracle clients installed. Please check ORACLE_HOME variable if it contains only one client.
One workaround I'm thinking about is creating two procedures for handling sequence. One to get value you start with:
create or replace function get_first from seq as return number
seqid number;
begin
select seq_name.nexval into seqid from dual;
return seqid;
end;
/
Then do your incrementation in script. And after that call second procedure to increment sequence:
create or replace procedure setseq(val number) as
begin
execute immediate 'ALTER SEQUENCE seq_name INCREMENT BY ' || val;
end;
/
This is not good approach but maybe it will solve your problem

Display multiple columns SQL query into PL/SQL stored procedure

I have a SQL query from which select multiple columns from "db_cache_advice". I want to create a PL/SQL stored procedure from the script.
Here is the SQL script, can someone show me a small sample from which i can pick up...
select name, size_for_estimate, size_factor, estd_physical_read_factor
from v$db_cache_advice;
If you are asking whether we can select multiple columns in pl/sql stored procedure or not..
then well yes, we can select multiple columns as well..
you have to give multiple variable list with respect to number of column you are selecting -
select name, size_for_estimate, size_factor, estd_physical_read_factor
into l_name, l_size_for_estimate, l_size_factor, l_estd_physical_read_factor
from v$db_cache_advice;
please note variable should be in sync, datatype should be match with column value fetching ...

Peoplecode, SQLEXEC not retrieving correct data

<-------PeopleCode------>
Hi,
I have a SQL query that i have tried executing using both SQLEXEC and SQL.fetch() but the problem is, when I am passing the values to parameters (:1,:2...) it does not return a row but when I hardcode the values in the where clause of the query itself, it retrieves the correct value.
Can anybody help?
My query looks similar to the following sample query :
Select * from PS_rec1 where emplid=:1 and plan_type=:2
it returns no data till i hardcode the values.
I have checked the values at the back end and some data is there to be fetched. Moreover, the same query retrieves data when ran in TOAD.
Have you tried outputting your binds to a log file just before you use them in your SQL statement?
If the binds aren't working, but literals are, then perhaps your binds don't contain the values that you expect them to.
You could also try explicitly setting the binds to the values that you're expecting just before the SQL statement. This will prove that the way you're passing in the binds is working correctly.
It required another update to the same record to get the values fetched in SQL exec.
M not sure what was the problem but i guess it might be that the previous update did not write the changes to the db even after an explicit commit.
Ok, you need to put your exact SQLExec statement in the question.
But, do you really have "Select * ..." in a SQLExec? How many columns are in your table? Since you mention the where clause, is your statement
SQLExec("select * from PS_rec where emplid=:1 and plan_type=:2", &var1, &var2, &vartocontainthewholerow);
Which will work in a SQL tool (toad) but probably does not work in AE or any type of Peoplecode program.
Now if your table has three columns, should you not have something like this:
SQLExec("select emplid, plan_type, column3 from PS_rec where emplid = :1 and plan_type=:2", &emplidIn, &plan_typeIn, &emplidOut, &plan_typeOut, &column3Out);
Notice that with three columns in the table that emplid and plan_type are two of them, you need to list all the columns you want, not asterisks '*'. Kind of silly to select the emplid and plan_type though.

Return REF CURSOR to procedure generated data

I need to write a sproc which performs some INSERTs on a table, and compile a list of "statuses" for each row based on how well the INSERT went. Each row will be inserted within a loop, the loop iterates over a cursor that supplies some values for the INSERT statement. What I need to return is a resultset which looks like this:
FIELDS_FROM_ROW_BEING_INSERTED.., STATUS VARCHAR2
The STATUS is determined by how the INSERT went. For instance, if the INSERT caused a DUP_VAL_ON_INDEX exception indicating there was a duplicate row, I'd set the STATUS to "Dupe". If all went well, I'd set it to "SUCCESS" and proceed to the next row.
By the end of it all, I'd have a resultset of N rows, where N is the number of insert statements performed and each row contains some identifying info for the row being inserted, along with the "STATUS" of the insertion
Since there is no table in my DB to store the values I'd like to pass back to the user, I'm wondering how I can return the info back? Temporary table? Seems in Oracle temporary tables are "global", not sure I would want a global table, are there any temporary tables that get dropped after a session is done?
If you are using Oracle 10gR2 or later then you should check out DML error logging. This basically does what you want to achieve, that is, it allows us to execute all the DML in a batch process by recording any errors and pressing on with the statements.
The principle is that we create an ERROR LOG table for each table we need to work with, using a PL/SQL built-in package DBMS_ERRLOG. Find out more. There is a simple extension to the DML syntax to log messages to the error log table. See an example here. This approach doesn't create any more objects than your proposal, and has the merit of using some standard Oracle functionality.
When working with bulk processing (that is, when using the FORALL syntax) we can trap exceptions using the built-in SQL%BULK_EXCEPTIONS collection. Check it out. It is possible to combine Bulk Exceptions with DML Error Logging but that may create problems in 11g. Find out more.
"Global" in the case of temporary tables just means they are permanent, it's the data which is temporary.
I would define a record type that matches your cursor, plus the status field. Then define a table of that type.
TYPE t_record IS
(
field_1,
...
field_n,
status VARCHAR2(30)
);
TYPE t_table IS TABLE OF t_record;
FUNCTION insert_records
(
p_rows_to_insert IN SYS_REFCURSOR
)
RETURN t_table;
Even better would be to also define the inputs as a table type instead of a cursor.

Resources