Oracle forms 10g - oracle

I'm new to oracle forms and i have a problem.
I have two multiple records blocks with same fields in the form.
I query data for one block, it gets populated .
Is where a way to copy all rows from populated block to 'copy' block?

Yes, there is a way. One is to manually type those values over there, but that's probably not what you want.
Another is to create a button (let's call it BTN_COPY) and create WHEN-BUTTON-PRESSED trigger on it. It'll look like code that follows (based on items that belong to Scott's EMP table); note that I can't test it, but - I hope it'll be OK.
declare
-- local variables; should contain all items you'd want to copy
l_empno emp.empno%type;
l_ename emp.ename%type;
l_job emp.job%type;
-- l_currec will contain current row number in the first block
l_currec number := 0;
-- l_exit will be used if we're at the end of the first block
l_exit varchar2(1) := 'N';
begin
loop
-- go to the source (first block) and the [last row you were in + 1]
go_block('first');
l_currec := l_currec + 1;
go_record(l_currec);
-- check whether this is the last row of the first block; if so, exit the loop
if :system.last_record = 'TRUE' then
l_exit := 'Y';
end if;
-- save current row's items
l_empno := :first.empno;
l_ename := :first.ename;
l_job := :first.job
-- go to the second block's bottom and create a new record
go_block('second');
last_record;
create_record;
-- put stored values into the second block's items
:second.empno := l_empno;
:second.ename := l_ename;
:second.job := l_job;
-- exit the loop if this was the last record to be copied
exit when l_exit = 'Y';
end loop;
end;

Related

Oracle forms 10g, copy multiple rows to another block

I'm new to oracle forms and i have a problem. I have two multiple records blocks with same fields in the form.
I query data for one block, it gets populated .
After that i need to copy all rows to new block. One helpful guy suggested following, but it keeps me in endless loop. Can you please help me resolve this?
:
declare
-- local variables; should contain all items you'd want to copy
l_empno emp.empno%type;
l_ename emp.ename%type;
l_job emp.job%type;
-- l_currec will contain current row number in the first block
l_currec number := 0;
-- l_exit will be used if we're at the end of the first block
l_exit varchar2(1) := 'N';
begin
loop
-- go to the source (first block) and the [last row you were in + 1]
go_block('first');
l_currec := l_currec + 1;
go_record(l_currec);`
-- check whether this is the last row of the first block; if so, exit the loop
if :system.last_record = 'true' then
l_exit := 'Y';
end if;
-- save current row's items
l_empno := :first.empno;
l_ename := :first.ename;
l_job := :first.job
-- go to the second block's bottom and create a new record
go_block('second');
last_record;
create_record;
-- put stored values into the second block's items
:second.empno := l_empno;
:second.ename := l_ename;
:second.job := l_job;
-- exit the loop if this was the last record to be copied
exit when l_exit = 'Y';
end loop;
end;
end;
if :system.last_record = 'true' then
:system.last_record returns 'TRUE' or 'FALSE' (in uppercase), so this IF statement will never be true. The 'true' in quotes must be 'TRUE'.

inserting of data not happening in oracle

I am new to plsql.I have a table where i need to insert the data(some dummy data).So,i thought to use plsql block and using For loop it will insert the data automatically.The plsql block is runned successfully,but the data are stored as empty.The block I tried is:
declare
v_number1 number;
v_number2 number;
v_number3 number;
begin
For Lcntr IN 2..17
LOOP
v_number1 := v_number1+1;
v_number2 := v_number2+2;
v_number3 := v_number3+3;
Insert into stu.result(res_id,stu_id,eng,maths,science) values (stu.seq_no.NEXTVAL,Lcntr,v_number1,v_number2,v_number3);
END LOOP;
end;
But my table is loaded as:(please ignore first two row data,i inserted it manually):
The data for eng,maths,science is not being inserted.why it is happening so?
That's because your variables are NULL. NULL + 1 = NULL as well.
If you modify declaration to
v_number1 number := 0;
v_number2 number := 0;
v_number3 number := 0;
something might happen.

bulk collect dynamic sql

I have to write a dynamic sql cursor where there are several possibilities in which the select query will be generated. Hence I am chosing dynamic and I am Using DBMS_SQL package to dynamically create a cursor and dynamically fetch the data.
However , Result set is going to be huge . around 11GB (there are 2.4 million records and the select statement will be approx 80 cols long assumning about 50Byte varchar per column)
Hence I cannot open the cursor at once . I want to know if there is a feature wherein i can fetch the data from the curosr keeping the curosr open for Blocks of say 1000 records at time(I will have to do this dynamically)
Please find the code attached which only fetches and prints the value of the columns (one sample case ) I want to use bul collect here \
Thanks
---------------code sample--------------------------------------
--create or replace type TY_DIMDEAL AS TABLE OF VARCHAR2(50) ;
create or replace procedure TEST_PROC (po_recordset out sys_refcursor)
as
v_col_cnt INTEGER;
v_ind NUMBER;
rec_tab DBMS_SQL.desc_tab;
v_cursor NUMBER;
lvar_output number:=0;
lvar_output1 varchar2(100);
lvar_output3 varchar2(100);
lvar_output2 varchar2(100);
LVAR_TY_DIMDEAL TY_DIMDEAL;
lvarcol varchar2(100);
begin
--
LVAR_TY_DIMDEAL := TY_DIMDEAL();
lvar_output1 := '';
v_cursor := dbms_sql.open_cursor;
dbms_sql.parse(v_cursor, 'select to_char(Field1) , to_char(fiel2) , to_char(field3) from table,table2 ', dbms_sql.native);
dbms_sql.describe_columns(v_cursor, v_col_cnt, rec_tab);
FOR v_pos in 1..rec_tab.LAST LOOP
LVAR_TY_DIMDEAL.EXTEND();
DBMS_SQL.define_column( v_cursor, v_pos ,LVAR_TY_DIMDEAL(v_pos),20);
END LOOP;
-- DBMS_SQL.define_column( v_cursor, 1 ,lvar_output1,20);
--DBMS_SQL.define_column( v_cursor, 2 ,lvar_output2,20);
--DBMS_SQL.define_column( v_cursor, 3 ,lvar_output3,20);
v_ind := dbms_sql.execute( v_cursor );
LOOP
v_ind := DBMS_SQL.FETCH_ROWS( v_cursor );
EXIT WHEN v_ind = 0;
lvar_output := lvar_output+1;
dbms_output.put_line ('row number '||lvar_output) ;
FOR v_col_seq IN 1 .. rec_tab.COUNT LOOP
LVAR_TY_DIMDEAL(v_col_seq):= '';
DBMS_SQL.COLUMN_VALUE( v_cursor, v_col_seq,LVAR_TY_DIMDEAL(v_col_seq));
dbms_output.put_line (LVAR_TY_DIMDEAL(v_col_seq));
END LOOP;
END LOOP;
end TEST_PROC;
Fetching data from a cursor in blocks of reasonable size, while keeping the cursor open, is one of PL/SQL Best Practices.
The above document (see Code 38 item) sketches an approach for when the select list is not known until runtime. Basically:
Define an appropriate type to fetch results into. Let's assume that all the returned columns will by of of type VARCHAR2:
-- inside DECLARE
Ty_FetchResults IS TABLE OF DBMS_SQL.VARCHAR2_TABLE;
lvar_results Ty_FetchResults;
Before each call to DBMS_SQL.FETCH_ROWS, call DBMS_SQL.DEFINE_ARRAY to enable batch fetching.
Call DBMS_SQL.FETCH_ROWS to fetch 1000 rows from the cursor.
Call DBMS_SQL.COLUMN_VALUE to copy the fetched data into your result array.
Process the results, record by record, in a FOR loop. Don't worry about the number of fetched records: if there are records to process, the FOR loop will run correctly; if the result array is empty, the FOR loop will not run.
Exit from the loop when the number of fetched records is less than the expected size.
Remember to DBMS_SQL.CLOSE the cursor.
Your loop body should look like this:
LOOP
FOR j IN 1..v_col_cnt LOOP
DBMS_SQL.DEFINE_ARRAY(v_cursor, j, lvar_results(j), 1000, 1);
END LOOP;
v_ind := DBMS_SQL.FETCH_ROWS(v_cursor);
FOR j IN 1..v_col_cnt LOOP
lvar_results(j).DELETE;
DBMS_SQL.COLUMN_VALUE(v_cursor, j, lvar_results(j));
END LOOP;
-- process the results, record by record
FOR i IN 1..lvar_results(1).COUNT LOOP
-- process a single record...
-- your logic goes here
END LOOP;
EXIT WHEN lvar_results(1).COUNT < 1000;
END LOOP;
-- don't forget: DBMS_CLOSE(v_cursor);
See also Doing SQL from PL/SQL: Best and Worst Practices.
LIMIT CLAUSE CAN COME TO RESCUE!
PL/SQL collections are essentially arrays in memory, so massive
collections can have a detrimental effect on system performance due to
the amount of memory they require. In some situations, it may be
necessary to split the data being processed into chunks to make the
code more memory-friendly. This “chunking” can be achieved using the
LIMIT clause of the BULK COLLECT syntax.
YOU CAN USE LIMIT CLAUSE AFTER BULK COLLECT INTO CLAUSE TO LIMIT YOUR RS.
AFTER YOU EXCEED TO LIMIT YOU CAN FETCH REMAINING ROWS.
SEE THIS ARTICLE
http://www.dba-oracle.com/plsql/t_plsql_limit_clause.htm

Oracle Forms list does not display values

I want to make list which will display values, like text item but in list.
My code:
DECLARE
rg_dept RecordGroup;
rg_dname VARCHAR2(4) := 'Name';
dlist_ID Item := Find_Item('PROJESCT.LIST_ID');
nDummy NUMBER;
BEGIN
rg_dept := Find_Group(rg_dname);
-- Delete any existing Group first
IF NOT Id_Null(rg_dept) THEN
Delete_Group(rg_dept);
END IF;
-- Now create a Record Group using a SQL query
-- Your Query must have a Label and a Value (two Columns)
-- and the data types must match your item type
rg_dept := Create_Group_From_Query(rg_dname,'SELECT department_name, to_char(department_id) FROM departments');
--Clear the existing List
Clear_List(dlist_ID);
-- Populate the Record Group
nDummy := Populate_Group(rg_dept);
-- Populate the List Item
Populate_List(dlist_ID ,rg_dept);
END;
If I make list item and add this code, form will display nothing; if I remove list, all is ok.
P.S. Trigger: when-list-item-change
I should recommend you to populate your lists from e.g. When-new-Form-Instance. As usual you will get a good idea what you need to do from Forms help (menu 'Help/Online Help'). This is a procedure I have made to simple populate list only by specifying the name of the list item and the select statement to populate the lsit item with.
PROCEDURE populate_list_item (
p_item_name VARCHAR2
, p_select VARCHAR2
) IS
l_rg_id RECORDGROUP;
l_list_id ITEM;
l_err_num PLS_INTEGER;
FUNCTION create_temp_group (
p_select VARCHAR2
) RETURN RECORDGROUP IS
l_rg_id RECORDGROUP;
l_group_name VARCHAR2(30) := 'TMP$RG';
BEGIN
l_rg_id := FIND_GROUP(l_group_name);
--Make sure that record group don't alreay exist
IF NOT ID_NULL(l_rg_id) THEN
DELETE_GROUP(l_rg_id);
END IF;
--Populate the temporary record group
l_rg_id := CREATE_GROUP_FROM_QUERY(l_group_name, p_select);
RETURN l_rg_id;
END create_temp_group;
BEGIN
l_rg_id := create_temp_group(p_select);
l_err_num := Populate_Group(l_rg_id);
--Allow for no data found in the selection query
IF l_err_num NOT IN (0, 1403) THEN
RAISE Form_Trigger_Failure;
END IF;
l_list_id := Find_Item(p_item_name);
IF ID_NULL(l_list_id) THEN
RAISE Form_Trigger_Failure;
END IF;
Populate_List(l_list_id, l_rg_id);
Delete_Group(l_rg_id);
END populate_list_item;
The When-New-Form-Instance is a form level trigger and should be under the form (instead of block or item):
The best thing to do is to build all your record groups at design time. It does not slow down the performance unless you have some huge, already slow form. Then populate your list items at run time. Always Copy/paste the code from Forms help.
--Oracle Forms Example: Create a record group from a query, and populate it.
DECLARE
rg_name VARCHAR2(40) := 'Salary_Range';
rg_id RecordGroup;
errcode NUMBER;
BEGIN
/*
** Make sure group doesn't already exist
*/
rg_id := Find_Group( rg_name );
/*
** If it does not exist, create it and add the two
** necessary columns to it.
*/
IF Id_Null(rg_id) THEN
rg_id := Create_Group_From_Query( rg_name,
'SELECT SAL-MOD(SAL,1000) BASE_SAL_RANGE,'
||'COUNT(EMPNO) EMPS_IN_RANGE '
||'FROM EMP '
||'GROUP BY SAL-MOD(SAL,1000) '
||'ORDER BY 1');
END IF;
/*
** Populate the record group
*/
errcode := Populate_Group( rg_id );
END;

How to get number of rows affected by a statement when inside that statement's trigger

I have a statement level trigger that fires whenever INSERT UPDATE or DELETE operations are performed on a table (called customers). I want to display a message (to DBMS_OUTPUT) containing the number of rows that were inserted/updated/deleted.
I just want one message for each triggering statement, eg
'4 rows were inserted into customers table'.
How can I access the number of rows that are affected by the triggering statement from INSIDE the trigger declaration, ie XXX in the code below:
CREATE OR REPLACE TRIGGER customer_changes_trigger_2
AFTER INSERT OR UPDATE OR DELETE ON customers
DECLARE
v_operation VARCHAR(10);
v_number_rows NUMBER;
BEGIN
v_number := XXX;
IF INSERTING THEN
v_operation := 'inserted';
END IF;
IF UPDATING THEN
v_operation := 'updated';
END IF;
IF DELETING THEN
v_operation := 'deleted';
END IF;
DBMS_OUTPUT.PUT_LINE
(v_number_rows|| ' rows were ' || v_operation || ' from customers.');
END;
Can't find anything in the documentation, any help appreciated!
One way is to use a global variable to track the number of rows as there is no other way to get the row count from a statement level trigger. You would then need three triggers... one statement level to initialise the variable before the statement is run, one row level to add one to the variable for each row, one statement level to use the row count however you wish. First, set up the variable and a few procedures to help it:
create or replace package PKG_ROWCOUNT is
NUMROWS number;
procedure INIT_ROWCOUNT;
procedure ADD_ONE;
function GET_ROWCOUNT
return number;
end PKG_ROWCOUNT;
/
create or replace package body PKG_ROWCOUNT as
procedure INIT_ROWCOUNT is
begin
NUMROWS := 0;
end;
procedure ADD_ONE is
begin
NUMROWS := Nvl(NUMROWS, 0) + 1;
end;
function GET_ROWCOUNT
return number is
begin
return NUMROWS;
end;
end PKG_ROWCOUNT;
/
The first trigger to initialise the variable:
create or replace trigger CUSTOMER_CHANGES_TRIGGER_1
before insert or update or delete
on CUSTOMERS
begin
PKG_ROWCOUNT.INIT_ROWCOUNT;
end;
The second to update per row:
create or replace trigger CUSTOMER_CHANGES_TRIGGER_2
after insert or update or delete
on CUSTOMERS
for each row
begin
PKG_ROWCOUNT.ADD_ONE;
end;
/
The third to display the total:
create or replace trigger CUSTOMER_CHANGES_TRIGGER_3
after insert or update or delete
on CUSTOMERS
begin
Dbms_output.
PUT_LINE(PKG_ROWCOUNT.GET_ROWCOUNT || ' rows were affected.');
end;
I'm not 100$ sure if it's available inside AFTER trigger body, but you can try examining sql%rowcount

Resources