i will like to ask a performance related question here my question is which approach is best
1 adding subquery in loop
declare
test varchar2(50);
FOR Lcntr IN 1..20
LOOP
update emp set empno='50' where empname=test;
END LOOP;
2 adding function call in loop or making the function of the above query and calling it in loop
declare
test varchar2(50);
FOR Lcntr IN 1..20
LOOP
temp:=update('argument');
END LOOP;
If your function update just call the same sql update, it dosen't matter are you call it directly of from stored function.
In common the best way is use one sql statement (update or merge) for update whole dataset what you need.
But you update are look like strange:
In first pl/sql block you declare variable test. And test is equal null. And after that you try update table by comparing with null - no any rows will be affected.
In second pl\sql block you declare variable test too, but use varable temp. It will raise error in compilation.
Related
I found a previous post (Cursors in BigQuery) where there exists a way to declare cursors on bigquery. This works well and good when the cursor subquery is not present as a parameter.
Currently I was going through FOR..IN EXECUTE construct in Netezza. It behaves extactly like a cursor construct except here, the sql present is a dynamic sql. This dynamic sql is first executed, after that the construct boils down to a simple cursor statement.
Consider the following use case, where the sub-query is present as a parameter.
CREATE or replace PROCEDURE myproc(varchar(256))
RETURNS INT4
LANGUAGE NZPLSQL
AS
BEGIN_PROC
declare
sqlstr alias for $1; ---- sqlStr is a parameter
r1 record;
begin
FOR r1 IN EXECUTE sqlstr ---- sqlStr is evaluated after that it boils down to cursor statement.
loop
insert into t1 values r1.c1;
end loop;
end;
END_PROC#
Is there a similiar way to declare cursors with subquery as a parameter on BigQuery ?
Formally, both LOOPs and EXECUTE IMMEDIATE are available in BigQuery and well documented.
Practically - using LOOP to mimic cursor for real table is extremely ineffective and quite a no-no in BigQuery unless you have use-case where this is the only way to go
But it is almost in 100% cases you can express your logic to be done in batch way (as opposed to using cursor)
At the same time if Table is not that big (like lookup tab le for example) - you can select table rows into array and than loop through arrays elements running execute immediate getting the result and inserting it into target table
I created a small loop to select the maximum value from a datablock in Oracle Forms. I have to do it this way, because the block sometimes gets global parameters from another form, or sometimes it has a different default where clause etc. It gets populated from different sources, so I can't create a cursor or I have to do it dynamically.
The loop I have, is declared like this:
loop
exit when :system.last_record = 'TRUE';
if (:block.number > v_max) then
v_max := :block.number;
end if;
next_record;
end loop;
Why is it so slow? It takes a long time to even check a block with 10 records.
Or is there an easier way to select the maximum from a column in a block?
Thanks in advance,
You probably have a lot of calculations and additional fetches in your post_query trigger? This gets executed for each row.
Alternatively you could set the block parameter "FETCH ALL RECORDS=true", and in the post_query trigger you update a global variable (which you have initialized with 0 in the pre-query trigger).
e.g.
pre_query:
:gobal.maxvalue := 0;
post_query (note this gets executed for each row):
if :block.number > :gobal.maxvalue then
:gobal.maxvalue := :block.number;
end if;
if :system.last_record = 'TRUE' then
do something with :global.maxvalue; -- we are on the last record of the query, so do something with the max value
end if;
after that you can use the global variable
Using HSQL 2.2.5 I need to shudder process one row at a time in a stored procedure, so I thought the "Iterated FOR" statement might do the trick for me. Unfortunately I don't seem to be able to make it work. It's supposed to look something like:
FOR SELECT somestuff FROM sometable DO
some random SQL statements
END FOR;
That leaves off a bit of the syntax, but it's close enough for now.
The problem seems to be that the statements inside the loop never execute. I've verified that my SELECT statement does indeed return something.
So let's get concrete. When I execute this stored procedure:
CREATE PROCEDURE b()
MODIFIES SQL DATA
BEGIN ATOMIC
DECLARE count_var INTEGER;
SET count_var = 0;
WHILE count_var < 10 DO
INSERT INTO TTP2 VALUES(count_var);
SET count_var = count_var + 1;
END WHILE;
END;
I get 10 rows inserted into table TTP2, with values 0 through 9. (TTP2 has just one column defined, of type INTEGER.)
But when I substitute a FOR statement for the WHILE like so:
CREATE PROCEDURE c()
MODIFIES SQL DATA
BEGIN ATOMIC
DECLARE count_var INTEGER;
SET count_var = 0;
FOR SELECT id FROM ttp_by_session FETCH 10 ROWS ONLY DO
INSERT INTO TTP2 VALUES(count_var);
SET count_var = count_var + 1;
END FOR;
END;
I get nothing inserted into TTP2. (I have verified that the SELECT statement returns 10 rows, one column of integers.)
When I leave the FETCH clause off I still get no results. ttp_by_session is a view, but the same thing happens with a bare table.
What am I doing wrong?
Thanks for the help.
This works fine with the latest version of HSQLDB. Try with the 2.3.0 release candidate snapshot from the HSQLDB web site.
When the FOR statement was initially added about two years ago, it had limited functionality. The functionality was extended in later versions.
I am using a Data Analysis tool and the requirement I have was to accept a value from the user, pass that as a parameter and store it in a table. Pretty straighforward so I sat to write this
create or replace
procedure complex(datainput in VARCHAR2)
is
begin
insert into dumtab values (datainput);
end complex;
I executed this in SQL Developer using the following statement
begin
complex('SomeValue');
end;
It worked fine, and the value was inserted into the table. However, the above statements are not supported in the Data Analysis tool, so I resorted to use a function instead. The following is the code of the function, it compiles.
create or replace
function supercomplex(datainput in VARCHAR2)
return varchar2
is
begin
insert into dumtab values (datainput);
return 'done';
end supercomplex;
Once again I tried executing it in SQL Developer, but I got cannot perform a DML operation inside a query upon executing the following code
select supercomplex('somevalue') from dual;
My question is
- I need a statement that can run the mentioned function in SQL Developer or
- A function that can perform what I am looking for which can be executed by the select statement.
- If it is not possible to do what I'm asking, I would like a reason so I can inform my manager as I am very new (like a week old?) to PL/SQL so I am not aware of the rules and syntaxes.
P.S. How I wish this was C++ or even Java :(
EDIT
I need to run the function on SQL Developer because before running it in DMine (which is the tool) in order to test if it is valid or not. Anything invalid in SQL is also invalid in DMine, but not the other way around.
Thanks for the help, I understood the situation and as to why it is illegal/not recommended
You could use the directive pragma autonomous_transaction. This will run the function into an independant transaction that will be able to perform DML without raising the ORA-14551.
Be aware that since the autonomous transaction is independent, the results of the DML will be commited outside of the scope of the parent transaction. In most cases that would not be an acceptable workaround.
SQL> CREATE OR REPLACE FUNCTION supercomplex(datainput IN VARCHAR2)
2 RETURN VARCHAR2 IS
3 PRAGMA AUTONOMOUS_TRANSACTION;
4 BEGIN
5 INSERT INTO dumtab VALUES (datainput);
6 COMMIT;
7 RETURN 'done';
8 END supercomplex;
9 /
Function created
SQL> SELECT supercomplex('somevalue') FROM dual;
SUPERCOMPLEX('SOMEVALUE')
--------------------------------------------------------------------------------
done
SQL> select * from dumtab;
A
--------------------------------------------------------------------------------
somevalue
Tom Kyte has a nice explanation about why the error is raised in the first place. It is not safe because it may depend upon the order in which the rows are processed. Furthermore, Oracle doesn't guarantee that the function will be executed at least once and at most once per row.
Just declare a variable to accept the return value, for example:
declare
retvar varchar2(4);
begin
retvar := supercomplex('somevalue');
end;
The select doesn't work because the function is performing an insert, if all it did was return a value then it would work.
Just execute the function in a dummy if ... end if; statement to ignore the return value:
exec if supercomplex('somevalue') then null; end if;
Or execute it as a parameter for put_line procedure to output the return value:
exec dbms_ouput ('result of supercomplex='||supercomplex('somevalue'));
result of supercomplex=done
I need to run big queries (that was a part of SP) and look at their results (just trying to find a bug in a big SP with many unions. I want to break it into parts and run them separately).
How can I do that if this SP have few parameters? I don't want to replace them in code, it would be great just to add declare in a header with a hardcode for this parameter.
I've tried something like this:
DECLARE
p_asOfDate DATE := '22-Feb-2011';
BEGIN
SELECT * from myTable where dateInTable < p_asOfDate;
END
But it says that I should use INTO keyword. How can I view this results in my IDE? (I'm using Aqua data studio)
I need to do that very often, so will be very happy if will find a simple solution
You are using an anonymous block of pl/sql code.
In pl/sql procedures you need to specify a target variable for the result.
So you first need to define a variable to hold the result in the declare section
and then insert the result data into it.
DECLARE
p_asOfDate DATE := '22-Feb-2011';
p_result myTable%ROWTYPE;
BEGIN
select * into p_result from myTable where dateInTable < p_asOfDate;
END
That said you will probaply get more than one row returned, so I would use
a cursor to get the rows separately.
DECLARE
CURSOR c_cursor (asOfDate IN DATE) is
select * from myTable where dateInTable < asOfDate;
p_asOfDate DATE := '22-Feb-2011';
p_result myTable%ROWTYPE;
BEGIN
OPEN c_cursor(p_asOfDate);
loop
FETCH c_cursor into p_result;
exit when c_cursor%NOTFOUND;
/* do something with the result row here */
end loop;
CLOSE c_cursor;
END
To output the results you can use something like this for example:
dbms_output.put_line('some text' || p_result.someColumn);
Alternatively you can execute the query on an sql command-line (like sqlplus)
and get the result as a table immediately.
I hope I understood your question correctly...
update
Here is a different way to inject your test data:
Use your tools sql execution environemnt to submit your sql statement directly without a pl/sql block.
Use a "&" in front of the variable part to trigger a prompt for the variable.
select * from myTable where dateInTable < &p_asOfDate;
The Result should be displayed in a formatted way by your tool this way.
I do not know about Aqua, but some tools have functions to define those parameters outside the sql code.