How to retain block position after a query -oracle forms - oracle

I have an oracle form with a data_block which displays 25 items.
On the form I have a scrollbar and a 'delete' button. When an item in the data block is selected, and the 'delete' button is pressed, it deletes the selected item from the database and then executes the data_block query.
By default, this returns the user to the top of the list.
I am trying to navigate to the record just before the one that is deleted from the list.
This can be done using the GO_RECORD(number) Built in Function(BIF) (assuming number is the saved value of :System.cursor_record).
And this is where I run into a problem. The GO_RECORD BIF will bring the record to the top or bottom of the displayed list of items. This can cause the list to shift up 20 items without warning.
i.e.
For example Records 23 - 47 from the data_block are being displayed, and record 33 is selected.
If record 33 is deleted and we use the function GO_RECORD(32), then the records diplayed will be 32-56 (effectively shifting the list down 9 records).
I'm assuming that in order to avoid this shift I will need to have some way of detemining the position of the record in the display (as opposed to the data_block).
Does anyone know if this functionality exists?
Or does anyone have another approach that might get me the same result?

first create this procedure as a program unit
PROCEDURE SYNC_BLOCK
-----------------------------------------------------------------------*
-- Synchronizes the display of any scrollable block.
-- After running an edit that loops through all records, this will
-- restore the block's display so that the same top record is again
-- at the top of the block's display.
-- Blk is the name of the block.
-- Rec_Num is the desired target current record.
-- Top_Rec is the original Top Record of the block captured
-- before the looping process began.
(BLK VARCHAR2,
REC_NUM NUMBER,
TOP_REC NUMBER) IS
BLK_ID BLOCK;
TOP_NEW PLS_INTEGER;
REC_N PLS_INTEGER;
--
Procedure Check_success is begin
If not form_success then
Raise form_trigger_failure;
End if;
End Check_success;
Procedure Go_Rec(rec_num number) is begin
Go_Record(Rec_num);
Check_Success;
End Go_Rec;
BEGIN
BLK_ID := FIND_BLOCK(BLK);
IF ID_NULL(BLK_ID) THEN
Message(' U72_GO_REC_SYNC_BLOCK: CANNOT FIND BLOCK '''||BLK||'''');
Raise Form_trigger_failure;
END IF;
IF BLK <> :SYSTEM.CURSOR_BLOCK THEN
GO_BLOCK(BLK);
Check_Success;
END IF;
IF :SYSTEM.CURSOR_RECORD <> REC_NUM THEN
GO_REC(REC_NUM);
END IF;
-- may need to re-set the display to the rows originally shown
TOP_NEW := GET_BLOCK_PROPERTY(BLK_ID, TOP_RECORD);
IF TOP_REC <> TOP_NEW THEN
IF TOP_REC < TOP_NEW THEN
IF :SYSTEM.CURSOR_RECORD <> TOP_REC THEN
GO_REC(TOP_REC);
END IF;
ELSE
REC_N := GET_BLOCK_PROPERTY(BLK_ID, RECORDS_DISPLAYED)
+ TOP_REC - 1;
IF :SYSTEM.CURSOR_RECORD <> REC_N THEN
GO_REC(REC_N);
END IF;
END IF;
SYNCHRONIZE;
-- Found that Sync caused focus change to different block. Fix here.
IF BLK <> :SYSTEM.CURSOR_BLOCK THEN
GO_BLOCK(BLK);
Check_Success;
END IF;
IF :SYSTEM.CURSOR_RECORD <> REC_NUM THEN
GO_REC(REC_NUM);
END IF;
END IF;
-- can't go_rec to NEW record, so need to test here
IF :SYSTEM.LAST_RECORD = 'TRUE'
AND REC_NUM = 1 + :SYSTEM.CURSOR_RECORD THEN
NEXT_RECORD;
Check_Success;
END IF;
--
END SYNC_BLOCK;
second this below five lines of code do exact what you want
xx:=GET_BLOCK_PROPERTY('blk',TOP_RECORD);
xxx:=GET_BLOCK_PROPERTY('blk',CURRENT_RECORD );
go_block('blk');
execute_query();
SYNC_BLOCK('blk',xxx,xx);
please do not hesitate to contact me if you require further information

-- save top record
l_top_rec:= GET_BLOCK_PROPERTY('EXP_DETAIL_BLK', TOP_RECORD);
l_cur_rec:= :SYSTEM.CURSOR_RECORD;
-- your actions
execute_query; // or othres actions...
-- set top record
go_block(block_name);
--
first_record;
loop
exit when GET_BLOCK_PROPERTY(block_name, TOP_RECORD) = l_top_rec;
next_record;
end loop;
go_record(l_top_rec);
--
loop
exit when :SYSTEM.CURSOR_RECORD = l_cur_rec or :SYSTEM.LAST_RECORD = 'TRUE';
next_record;
end loop;

Related

Highlight the value by using visual attributes of column after searching in oracle form in a button trigger

Edited Version---
IN this oracle form i have fetched the data using cursor and i want to highlight values which are starting from certain alphabet or word in column by clicking on search button and I have used visual attribute block and use this code in WHEN_BUTTON_PRESSED Trigger but it is not working .Did I used wrong trigger because on compiling there is no error but not executing on running
declare
cursor emp_cur is
select e.employee_id,e.last_name,e.salary,e.hire_date,e.department_id,d.department_name
from employees e,departments d
where e.department_id=d.department_id and e.department_id = :dept.deptid;
begin
first_record;
for i in emp_cur
loop
:emp.empid := i.employee_id;
:emp.ename := i.last_name;
:emp.sal := i.salary;
:emp.hire_date := i.hire_date;
:emp.deptid := i.department_id;
:emp.dname := i.department_name;
next_record;
end loop;
end;
created another button to search the highlighed valueenter image description here
go_block('emp');
begin
loop
first_record;
if lower(:emp.ename) like :emp.txt_search||'%' then
set_item_instance_property('emp.ename',current_record,visual_attribute,'VA');
else
if :system.last_record = 'TRUE' THEN
exit;
else next_record;
end if;
end if;
end loop;
go_item('txt_search');
end;

Not getting the desired results

enter code hereI have a Problem. Below pl/sql used to be working before and now i dont know whats happening... I want to insert records into a table called incoming from an interactive report using a check box
my sql is
SELECT apex_item.checkbox2(1,filenumber)
|| apex_item.hidden(2,filename)
|| APEX_ITEM.hidden(3,'&APP_USER. ')
|| APEX_ITEM.hidden(4,volume)
|| APEX_ITEM.hidden(6,filename)
as "SELECT",
FILENUMBER,
FILENAME,
LOCATION,
OPENDATE,
CLOSEDDATE,
VOLUME,
SUB,
temporary,
registryid,
STATUS
from REGISTRY
my pl/sql is
begin
for idx in 1 .. apex_application.g_f01.count
loop
if apex_application.g_f01(idx) is not null then
insert into incoming
(filenumber,
filename
)
values
(apex_application.g_f01(idx),
apex_application.g_f02(idx)
);
end if;
end loop;
end;
and all this happens after process..this was working fine.. However from recent the problem i am having is the pl/sql gives me the correct filenumber but the incorrect filename.
e.g
lets say the ir report has
filenumber filename
1 aaron
2 kerron
3 Joshua
when i select number 2 (second record) the result in the incoming table will be
filenumber filename
2 aaron
its always selecting the first record once it falls in the apex_item.hidden.
if i reverse it and put
SELECT apex_item.checkbox2(1,filename)
|| apex_item.hidden(2,filenumber)
the filename is correct and the file number will do what i explained above which is if i choose the second record i will get
filenumber filename
1 kerron
when i add
begin
for idx in 1 .. apex_application.g_f01.count loop
for i in 1..apex_application.g_f02.count loop
if apex_application.g_f01(idx) is not null then
insert into INCOMINGREQUESTNOTIFICATION
(requestedfile,filenumber
)
values
(apex_application.g_f01(idx),
apex_application.g_f02(i)
);
end if;
end loop;
end loop;
end;
#romeuBraga i am getting all 3 rows not the selected one can you tell me what am doing wrong
You need a hidden item to store the ID.
*1 and 2 store the same information
select column1,
column2,
column3,
apex_item.hidden(p_idx => 1,
p_value => code) ||
apex_item.checkbox2(p_idx => 2,
p_value => code) CheckBox,
other items
from x
in this case, you need this pl/sql to get the correct row values.
begin
for i in 1..apex_application.g_f01.count loop
for j in 1..apex_application.g_f02.count loop
if apex_application.g_f01(i) = apex_application.g_f02(j) then
--insert something here
end if;
end loop;
end loop;
end;

PL/SQL -If exists in Table type of varchar2 not working

I am using a huge table which loops inside a cursor so i thought rather than querying on each iteration, put the particular data in a Table type and then check data exists inside the loop.
declare
type type_product_list is table of varchar(6);
product_list type_product_list;
begin
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
FOR i IN 1..product_list.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(product_list(i)); -- This line printing properly.
END LOOP;
IF product_list.EXISTS('00029') THEN -- This condition always fails
DBMS_OUTPUT.PUT_LINE('Found');
ELSE
DBMS_OUTPUT.PUT_LINE('Not Found');
END IF;
end;
Output
00029
00030
00031
00032
..... other data
NOT FOUND
Please help, how can I get the IF block executed.
*Update
Main purpose of this problem is to call a function inside the IF block, and if block itself will be inside a cursor loop which gives dynamic product id in each iteration, i.e. if the product id exists then call that function.
begin
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
OPEN cur_cms_scriptdtl();
LOOP
FETCH cur_cms_scriptdtl INTO productId, productName;
EXIT WHEN cur_cms_scriptdtl%notfound;
IF product_list.EXISTS(productId) THEN
-- Function call
END IF;
END LOOP;
CLOSE cur_cms_scriptdtl;
After some digging and help from Oracle docs, I was able to get it without FOR LOOP.
The helping angel here is : member of
BEGIN
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
OPEN cur_cms_scriptdtl();
LOOP
FETCH cur_cms_scriptdtl INTO productId, productName;
EXIT WHEN cur_cms_scriptdtl%notfound;
IF productId member of product_list THEN
-- Function call
END IF;
END LOOP;
CLOSE cur_cms_scriptdtl;
In collections, exists method receives as parameter an index, not a value.
IF product_list(i) = '00029' THEN
Try this:
DECLARE
type type_product_list is table of varchar(6);
product_list type_product_list;
vFound BOOLEAN := false;
BEGIN
FOR i IN 1..product_list.COUNT LOOP
dbms_output.put_line(product_list(i));
IF product_list(i) = '00029' THEN
vFound := true;
exit;
END IF;
END LOOP;
IF vFound THEN
dbms_output.put_line('Found');
ELSE
dbms_output.put_line('Not Found');
END IF;
END LOOP;

PL/SQL - Pre actions if cursor is found

I have a simple cursor like this:
CURSOR emp_cur
IS
SELECT *
FROM employee
WHERE age > 20;
In my procedure, I want to do some pre-actions only if there are employee in cursor. After that pre-action, I process all rows.
I need this because only if exists employee in that cursor i need to cleanup some tables, otherwise i should "RETURN".
so the code could be:
OPEN emp_cur;
/* Here i need to do pre-action only if emp_cur has rows*/
IF /* has rows*/
THEN
/* do some actions*/
END IF;
LOOP
FETCH emp_cur INTO emp_rec;
EXIT WHEN emp_cur%NOTFOUND;
END LOOP;
CLOSE emp_cur;
For now, i have a "dirty" solution where i open cursor:
First to check if there are rows
Do pre-action and close
Open/fetch again to process rows, and close again
First to check if there are rows
You cannot know about the rows until you FETCH.
From documentation link ,
After a cursor or cursor variable is opened but before the first
fetch, %FOUND returns NULL. After any fetches, it returns TRUE if the
last fetch returned a row, or FALSE if the last fetch did not return a
row.
Once you have fetched the rows, then before processing the rows, you could use %FOUND.
For example,
OPEN c1;
LOOP
FETCH c1 INTO my_ename, my_salary;
IF c1%FOUND THEN -- fetch succeeded
-- Do something
ELSE -- fetch failed, so exit loop
EXIT;
END IF;
END LOOP;
Thinking a little i've wrote this procedure that avoid an IF inside the loop. I know, is a little "strange" but is the only thing i've think works:
OPEN emp_cur;
FECTH emp_cur INTO emp_rec;
IF emp_cur%FOUND
THEN
-- pre actions
END IF;
LOOP
EXIT WHEN emp_cur%NOTFOUND;
-- do something in the loop
FECTH emp_cur INTO emp_rec; -- First fetch was done before the if
END LOOP;
CLOSE emp_cur;

How can I prevent the user from creating more than one record at a time in multirow block?

I have a form with a multi-row block based on a table. The requirement is that the user can only enter 1 row into the block at a time and commit it. They should not be allowed to create a second row before committing the first.
I tried using a WHEN-CREATE-RECORD trigger like this:
if :system.block_status = 'CHANGED' then
alert('Can only create one record at a time');
end if;
However, this prevents me creating a new record even after committing changes.
One way would be to loop through all records and if the second record isn't null, alert the user.
DECLARE
n_index NUMBER := 0;
BEGIN
Go_block('block_name');
first_record;
WHILE :SYSTEM.last_record != 'TRUE' LOOP
next_record;
IF :block_name.item_name IS NOT NULL THEN --replace item_name with one which the user will enter all the time
n_index := n_index + 1;
END IF;
IF n_index > 0 THEN
Alert('Only one record can be created at a time!');
END IF;
END LOOP;
END;
BEGIN
-- WHEN-NEW-RECORD-INSTANCE
IF :SYSTEM.CURSOR_RECORD > 1 THEN
DELETE_RECORD;
END IF;
END;

Resources