First I have loop in pl/sql example (EX 1)
begin
declare
l_string varchar2(4000);
begin
:P15_URL_PARAMETER := '';
FOR i IN 1..APEX_APPLICATION.G_F01.COUNT LOOP
l_string := l_string || APEX_APPLICATION.G_F01(i) || '-';
END LOOP;
:P15_URL_PARAMETER := l_string;
end;
end;
After P15_URL_PARAMETER field get value from above plsql I need call
redirect to url example (EX 2)
javascript:var a = window.open('f?p=800:105:&APP_SESSION.:.....xyz........&P15_URL_PARAMETER.');
In this moment, first on BUTTON_1 I call process (EX 1) and then P15_URL_PARAMETER get value on second button BUTTON_2 call redirect to url (EX 2). All work fine, but is it possible (EX 1 and EX 2) call on one button click?
Tnx
I guess so. That would be done by creating a dynamic action with two true actions:
one is "Execute PL/SQL Code" (which is the first piece of code you posted)
another one is "Execute JavaScript Code" (which is the second code you posted)
Related
I am getting the ORA-06511: PL/SQL: cursor already open ERROR.
Not sure why I am getting this error since I am closing my cursor.
Please see code below.
BEGIN
OPEN findem; ---OPENING HERE!
FOR crfindem IN findem LOOP
FETCH findem into other1, other2, other3;
l_CollectionOfRows(Counter).tmps_key := other1;
l_CollectionOfRows(Counter).tmps_cfb_rate := other2;
l_CollectionOfRows(Counter).tmps_engagement_pay_rate := other3;
Counter := Counter + 1;
END LOOP;
CLOSE findem;---CLOSING HERE!
FORALL i IN l_CollectionOfRows.FIRST .. l_CollectionOfRows.LAST
UPDATE Base.Table
SET MARGIN = :PAGE56_MARGIN,
PERCENT = :PAGE56_MARGIN + l_CollectionOfRows(i).rate,
PAY_RATE = (l_CollectionOfRows(i).pay_rate * (:PAGE56_MARGIN + l_CollectionOfRows(i).rate)) + l_CollectionOfRows(i).pay_rate
WHERE tmps_key = l_CollectionOfRows(i).tmps_key;
END;
I read from some online threads that for every Insert/Update statement, Oracle will create an implicit cursor. If this is the case how do you treat those implicit cursors that Oracle creates?
You are getting that error because you are opening the same cursor twice: the FOR construct already does all these things for you:
FOR opens the cursor
FOR implicitly declares a record variable (the one named crfindem, in your code) that will receive the values for each row read from the cursor
FOR loops on every row and assigns the values of the current row to the crfindem variable
FOR automatically closes the cursor at the end of the loop
so you don't need any OPEN/CLOSE/FETCH .. INTO commands if you are using a FOR loop:
see this simple example: itjust works.
declare
cursor cur is select * from user_tab_comments;
begin
for c in cur loop
DBMS_OUTPUT.PUT_LINE( c.table_name || ' - ' || c.comments);
end loop;
end;
but if i try to open the cursor before using the for loop, I will get your same error because the cursor is already open and the for construct is trying to open it again:
declare
cursor cur is select * from user_tab_comments;
begin
open cur; -- this is not needed and will cause problems
for c in cur loop --! ERROR: here I am trying to open AGAIN the same cursor
DBMS_OUTPUT.PUT_LINE( c.table_name || ' - ' || c.comments);
end loop;
end;
so, you either must choose if you want to write this code:
declare
cursor cur is select * from user_tab_comments;
begin
for c in cur loop
DBMS_OUTPUT.PUT_LINE( c.table_name || ' - ' || c.comments);
end loop;
end;
or avoid using the FOR construct and do all the open/fetch/close operations by yourself, by writing this:
declare
-- I cant' use "select *" here:
-- if I use "fetch into" to a precise list of variables,
-- I have to extract exactly the fields I want to assign:
cursor cur is
select table_name,comments
from user_tab_comments;
tabname varchar(100);
tabcomment varchar2(4000);
begin
open cur;
loop
fetch cur into tabname,tabcomment;
exit when cur%notfound;
DBMS_OUTPUT.PUT_LINE( tabname || ' - ' || tabcomment);
end loop;
close cur;
end;
Your error is that your code is trying to do both these things at the same time.
you should have written this:
-- OPEN findem; NO NEED TO OPEN THE CURSOR (when using FOR)
FOR crfindem IN findem LOOP
--- FETCH findem into other1, other2, other3; FOR ALREADY DOES THIS: the values are in crfindem
l_CollectionOfRows(Counter).tmps_key := crfindem.name_of_the_first_field;
l_CollectionOfRows(Counter).tmps_cfb_rate := crfindem.name_of_the_second_field;
l_CollectionOfRows(Counter).tmps_engagement_pay_rate := crfindem.name_of_the_third_field;
Counter := Counter + 1;
END LOOP;
--- CLOSE findem; NO NEED TO CLOSE THE CURSOR (when using FOR)
Now let me add some considerations about your code (and about this example):
I don't see where you initialize your Counter variable: you MUST initialize it to 0 before entering the loop, because otherwise its initial value will be NULL and will stay null for the whole operation because (NULL + 1) evaluates again to NULL.
I don't see how your cursor is declared, so I don't know the names of the fields it extracts. in the code above I used the "fake" names name_of_the_first_field, name_of_the_second_field, name_of_the_third_field... but you must use the correct field names returned by your query
if your cursor returns some calculated value (like "select 1+2, sysdate, null from dual") you must assign a name to the calculated column to make it accessible by giving an alias to each calculated column you extract ("select 1+2 AS first_name, sysdate AS second_name, null as third_name from dual")
Edit... another info: you don't really need to declare a variable for each field even when you are explicitly using open/fetch/close: you can declare a RECORD variable (that will contain all column values with the same column names, exactly like the for loop does) by using the %ROWTYPE syntax. my example becomes like this, using %rowtype:
declare
cursor cur is select * from user_tab_comments;
-- here I am declaring a variable named c that is a RECORD variable:
-- it can contain a whole row returned by cursor cur
c cur%rowtype;
begin
open cur;
loop
fetch cur into c;
exit when cur%notfound;
DBMS_OUTPUT.PUT_LINE( c.table_name || ' - ' || c.comments);
end loop;
close cur;
end;
I'm trying to generate an Interactive-Report in Apex with a SQL-Statement which lies in a page item (:P10_SQL), for example: select 1 from dual.
declare
l_sql VARCHAR2(4000 CHAR);
Begin
select V('P10_SQL') into l_sql from dual;
return l_sql;
End;
The Report has the type PL/SQL Function Body returning SQL Query.
Apex shows an error
ORA-20999: WWV_FLOW_EXEC.NULL_QUERY_RETURNED_BY_FUNCTION
Somebody gets an idea?
Apex acts kind of crazy as it doesn't always want to accept code I write (which is perfectly valid), saying that function doesn't return anything. Oh well.
Therefore, my function that returns SQL query was written in stages. The following bullets represents attempts I made; all of them are OK. The final version - the one that runs right now is as simple as return :P77_SQL; (I'm on page 77)
return 'select dummy from dual'
declare
l_str varchar2(4000);
begin
l_str := case when :P77_SQL is null then 'select dummy from dual'
else :P77_SQL
end;
return l_str;
end;
return :P77_SQL;
However: you can't use interactive report, has to be a classic report because not all tables you'll have as a source will have the same column names (unless you use aliases and match number and datatypes, which is rather complicated).
But, if you use a classic report, then turn "Use generic column names" on and set desired number of generic columns (I set it to 10; you'll know what to do in your case).
My P77_SQL text item submits the page when I press ENTER, which causes the report to refresh.
A few examples:
Like I posted in a previous thread I want to create a little program which edits one line in a .ini file. Now I have implemented a button but don't further. I basically want to implement the following scenario:
1) Click Button
2) Because of button click, program opens .txt/.ini file (in background) the file is located in the same folder
3) One word in text file is changed with new word
4) file gets saved
5) message pops up
procedure TLauncher.ButtonClick(Sender: TObject);
var
begin
ShowMessage('.Ini-File was edited')
end;
That's simple to do, if you split what you want to do into procedures that only
do one thing each.
Assume your form has a string variable IniFileName which you initialize however
you want, e.g. using a TOpenDialog. Then you can have
procedure TForm1.LoadIni;
begin
Memo1.Lines.LoadfromFile(IniFileName);
end;
procedure TForm1.SaveIni;
begin
Memo1.Lines.SaveToFile(IniFileName);
end;
procedure TForm1.Button1Click;
begin
if OpenDialog1.Execute then begin
IniFileName := OpenDialog1.FileName;
LoadIni;
end;
end;
procedure TForm1.Button2Click;
begin
SaveIni;
ShowMessage(IniFileName + ' saved to disk');
end;
I'm using Oracle Forms 10g, on a Oracle Database version 7.
I have a data block who is refreshed (new execute_query) from two different ways:
1.A button how implement this:
PROCEDURE refresh
IS
ID NUMBER;
BEGIN
ID := :myblock.id;
GO_BLOCK ('myBlock');
EXECUTE_QUERY;
-- Keep the record selected after the refresh
POSITION (ID);
END;
PROCEDURE POSITION (ID IN NUMBER)
IS
L_record NUMBER (5) := NULL;
BEGIN
GO_BLOCK ('myBlock');
GO_ITEM ('myBlock.ID');
FIRST_RECORD;
LOOP
IF :myblock.id = myID THEN
L_record := GET_BLOCK_PROPERTY ('myBlock', CURRENT_RECORD);
END IF;
EXIT WHEN :SYSTEM.LAST_RECORD = 'TRUE' OR :myblock.ID = myID;
NEXT_RECORD;
END LOOP;
IF L_record IS NOT NULL THEN
GO_RECORD (L_record);
END IF;
END;
2.The other is one other button who do this:
PROCEDURE newRefresh
IS
ID NUMBER;
BEGIN
ID := :myblock.id;
refresh;
POSITION (ID);
END;
Ignoring the reason of this two buttons, my problem is when I call the second button, the first call of POSITION procedure takes too long (because we have a lot of records and POST_QUERY trigger), but the second call of the same procedure is very fast.
What is the reason of this behaviour? Is there a fastest way of positioning the focus on the same record selected before?
Why is it slow? Who knows ... All we can do is to blindly guess and still be VERY far from actual reason. Too few data to compute. I'd suggest you to run the form in debug mode (as Forms 10g allows it) and trace its execution to see what's going on.
As of faster positioning: consider this approach:
create a parameter, let's call it position
refresh button(s) would:
-- save current position
:parameter.position := :system.trigger_record;
go_block('myBlock');
execute_query;
-- go to previously saved position
go_record(:parameter.position);
(BTW, are you really using Oracle database version 7.x? Whoa!)
I have created a Function from Oralce DB and used it as input to Spotfire report. The reason why i used a function instead of view is because the parameters had some complex logic operations and i was not able to get that done in a view.
Coming to the report i have built. Currently i am using 2 parameters in the function and i am taking both the values from Spotfire text area in Data on Demand mode. Issue is that unless i enter values for both parameters i wont get the output. My requirement is that i need to add few more parameters for the report which i can but i need to set up the function and the settings in Spotfire such that if 5 parameters are there , if users enters one value for just one parameter report should run for that parameter. So the Functions needs to be in such a way that if value is entered that should be taken and if its left empty then that should not be considered. leaving the Spotfire part if the Function is built with the specifics mentioned by me i can implement it directly.
I have got different solutions from everywhere and i am not able to implement anything properly. I am updating all the examples and need help in figuring out the right one and correcting it or to do it in a completely different manner
Code Type 1:
create or replace function Function_test(p1 varchar2='',p2 varchar2='',p3 varchar2)
return SYS_REFCURSOR as
my_cursor SYS_REFCURSOR;
begin
open my_cursor for
select distinct
x.c1
x.c2
x.c3
from x
where x.c1=p3
and (p1='' or x.c2=p1)
and (p2='' or x.c3=p2);
return my_cursor;
end;
The above code seems to be an example from MSSQL and i am able to get the logic but dont know the right way to implement in Oracle. When i tried i just got lot of errors.
Code Type 2:
create or replace function Function_delete(param1 Varchar2, param2 varchar2)
RETURN Varchar2 IS
ssql varchar2(3000);
test varchar2(1000);
begin
ssql := 'select col1,col2 from table_x';
if param1 is null and param2 is not null then
ssql := ssql || ' Where col2='''|| param2 ||'''';
end if;
if param1 is not null and param2 is null then
ssql := ssql || ' Where col3= ''' || param1 ||'''';
end if;
if param1 is not null and param2 is not null then
ssql := ssql || ' Where col3 = ''' || param1 || ''' and col2='''|| param2 ||'''';
end if;
dbms_output.put_line(ssql);
execute immediate ssql into test;
return test;
--EXCEPTION
-- WHEN OTHERS THEN
-- return 'Hello';
end Function_delete;
In the above example i am not able to implement the logic right in Spotfire cos it requires columns to get the data. Ultimately i need a code that accepts no of parameters that are given by the user rather than working only when all parameters are given. It needs to have columns visibly displayed since that way i can implement the same in Spotfire Reports.
you can try this:
create or replace function Function_test(p1 in varchar2,p2 in varchar2,p3 in varchar2)
return SYS_REFCURSOR as
my_cursor SYS_REFCURSOR;
begin
open my_cursor for
select
1
from
dual
where 1=1
and '1'=p1
and '2'=p2
and '3'=p3 ;
return my_cursor;
end;