How to Get datablock default where that oracle forms generate with Enter-query action - oracle

I am working with oracle forms 6i.
Simply I am using database block with these items :
Employees: employee_id , job_id , department_id , manager_id
note: employees is the data-block name .
For example: when end user click enter-query button and write 50 in department_id item and then click execute-query button; data block will return all employees who are in department 50.
My question is : How can I get the WHERE CLAUSE that oracle forms generate when returned desired data?...
I used this code in pre-query trigger
:parameters.whr:=get_block_property('employees',default_where);
But it returned no results

You're close, but not close enough. It is the GET_BLOCK_PROPERTY you need, but use its LAST_QUERY parameter. It will return SQL statement of the last query in the specified block.
Alternatively, use system variable :SYSTEM.LAST_QUERY (returns the same result).
Here's an example( the following code might be put in KEY-EXEQRY trigger of employees block ):
declare
l_lastq varchar2(4000);
l_where_position number;
l_where_clause varchar2(4000);
begin
execute_query;
l_lastq := :system.last_query;
l_where_position := instr(lower(l_lastq), 'where');
if l_where_position > 0 then
l_where_clause := substr(l_lastq, l_where_position, length(l_lastq));
message('WHERE clause: ' || l_where_clause);
end if;
end;

Related

In Oracle Apex how do you set the table name of a report using a page item?

I have many tables to choose from, and an Interactive Report whose table name needs to be set using a page item called P4_TABLE_NAME.
Other posts say that this can only be done with PL/SQL. So I set the Source of the Interactive Report to "Function Body returning SQL Query" and the Language to PL/SQL. This is the code I then used:
declare
v_query varchar2(500);
begin
v_query := 'select * from '||:P4_TABLE_NAME ;
return v_query;
end;
This code gives the error "invalid table name". I also tried it on a Classic Report and it gives the same error.
That's kind of tricky because report should know which columns you're selecting unless you set it to use generic column names. It means that no matter which table you query, column names will be col1, col2, col3, ...
Here's how:
I created a new page with a Classic report region and a Select list item (which returns tables I have in my schema)
report's source is a function body that returns a query, just as you put it:
declare
v_query varchar2(500);
begin
v_query := 'select * from ' || :P4_TABLE_NAME;
return v_query;
end;
don't forget to set "Use generic column names" to "Yes"!
Item is trivial:
I set it to "Submit page" (so that when I choose a new table, report's contents changes)
Select list item's query:
select table_name d, table_name r
from user_tables
order by table_name
Run the page:

ORACLE APEX Item values setting with PL\SQL Expression source facing PLS-00103 warning

I am trying to work on setting value to a hidden item that is running at the background of the APEX page using PL\SQL expression as there is some checking need to be done. But somehow I am having some 'PLS-00103' Encountered the symbol "Declare".... error when compile.I would like to seek for help on how to solve this. Thank you
enter image description here
DECLARE
p_batch_id_stg NUMBER;
p_batch_id_fail NUMBER;
p_final_batch_id NUMBER;
BEGIN
SELECT
BATCH_ID INTO p_batch_id_stg
FROM
NIOE_ORDER_HEADER_STG_V
WHERE
BATCH_ID !='' OR BATCH_ID IS NOT NULL
ORDER BY
BATCH_ID DESC
FETCH FIRST 1 ROWS ONLY;
SELECT
BATCH_ID INTO p_batch_id_fail
FROM
NI.NI_OM_ORDER_IMPORT
WHERE
BATCH_ID !='' OR BATCH_ID IS NOT NULL
ORDER BY
BATCH_ID DESC
FETCH FIRST 1 ROWS ONLY;
IF p_batch_id_fail > p_batch_id_stg THEN
p_final_batch_id := p_batch_id_fail;
ELSIF p_batch_id_stg > p_batch_id_fail THEN
p_final_batch_id := p_batch_id_stg;
END IF;
RETURN p_final_batch_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
/
... using PL\SQL expression
Well, this is not a PL/SQL expression. It is written in PL/SQL, but it represents a Function Body that returns some value.
It is not clear where exactly you're doing this (is it that item's "Source" or "Default" value?), but - nonetheless, I'd suggest you to change type to "Function Body".

PLS-00357: Table,View Or Sequence reference 'JANUARY_2020' not allowed in this context

I am using this code to see if it will work for a procedure. I want to be able to make a procedure in which i can decide what data to extract by typing the time ('jan-2020') in which it is recorded and also to decide in which table i want to place the data in (january_2020). i get the error that the table is not able to be used in this context. What do i have to change in the code to be in the right context?
Is it because i am using dynamic sql in a loop that requires the loop to be executed to put the data in the table? or is it because i am using %rowtype as the attribute for the table ALL_DATA to create its own columns? If it is any of these what should i do to change it?
DECLARE
time_v varchar2(9);
table_v varchar2(200);
sql_code varchar2(300);
TYPE Copied_Table IS TABLE OF Gastos%ROWTYPE;
All_Data Copied_Table;
BEGIN
time_v := 'jan-2020';
SELECT *
BULK COLLECT INTO All_Data FROM Gastos
Where TO_CHAR(DATE_, 'MON-YYYY') = UPPER(time_v);
FOR I in All_Data.First .. All_Data.Last LOOP
sql_code := 'INSERT INTO :table_v ( DATE_, DESCRIPTION, ORIGINAL_DESCRIPTION, AMOUNT,
TRANSACTION_TYPE, CATEGORY, ACCOUNT_NAME)
Values ( ALL_Data(i).date_, ALL_Data(i).description, ALL_Data(i).original_description,
ALL_Data(i).amount, ALL_Data(i).transaction_type, ALL_Data(i).category, ALL_Data(i).account_name)';
table_v := january_2020;
execute immediate sql_code
using table_v;
END LOOP;
END upload_monthly_expenses;
Pass table name as input parameter and replace bind variable with normal variable for the table name and concatenate it to the DML statement.Modify your code as below,
CREATE OR REPLACE PROCEDURE upload_monthly_expenses(table_v IN VARCHAR2,time_v IN VARCHAR2) AS
DECLARE
sql_code varchar2(300);
TYPE Copied_Table IS TABLE OF Gastos%ROWTYPE;
All_Data Copied_Table;
BEGIN
SELECT *
BULK COLLECT INTO All_Data FROM Gastos
Where TO_CHAR(DATE_, 'MON-YYYY') = UPPER(time_v);
FOR I in All_Data.First .. All_Data.Last LOOP
sql_code := 'INSERT INTO '||table_v||' ( DATE_, DESCRIPTION, ORIGINAL_DESCRIPTION, AMOUNT,
TRANSACTION_TYPE, CATEGORY, ACCOUNT_NAME)
Values ( ALL_Data(i).date_, ALL_Data(i).description, ALL_Data(i).original_description,
ALL_Data(i).amount, ALL_Data(i).transaction_type, ALL_Data(i).category, ALL_Data(i).account_name)';
execute immediate sql_code;
END LOOP;
END;
From a PL/SQL block procedure can be executed as below,
BEGIN
upload_monthly_expenses('jan-2020','january_2020');
END;

Insert into not working on plsql in oracle

declare
vquery long;
cursor c1 is
select * from temp_name;
begin
for i in c1
loop
vquery :='INSERT INTO ot.temp_new(id)
select '''||i.id||''' from ot.customers';
dbms_output.put_line(i.id);
end loop;
end;
/
Output of select * from temp_name is :
ID
--------------------------------------------------------------------------------
customer_id
1 row selected.
I have customers table which has customer_id column.I want to insert all the customer_id into temp_new table but it is not being inserted. The PLSQL block executes successfully but the temp_new table is empty.
The output of dbms_output.put_line(i.id); is
customer_id
What is wrong there?
The main problem is that you generate a dynamic statement that you never execute; at some point you need to do:
execute immediate vquery;
But there are other problems. If you output the generated vquery string you'll see it contains:
INSERT INTO ot.temp_new(id)
select 'customer_id' from ot.customers
which means that for every row in customers you'll get one row in temp_new with ID set to the same fixed literal 'customer_id'. It's unlikely that's what you want; if customer_id is a column name from customers then it shouldn't be in single quotes.
As #mathguy suggested, long is not a sensible data type to use; you could use a CLOB but only really need a varchar2 here. So something more like this, where I've also switched to use an implicit cursor:
declare
l_stmt varchar2(4000);
begin
for i in (select id from temp_name)
loop
l_stmt := 'INSERT INTO temp_new(id) select '||i.id||' from customers';
dbms_output.put_line(i.id);
dbms_output.put_line(l_stmt);
execute immediate l_stmt;
end loop;
end;
/
db<>fiddle
The loop doesn't really make sense though; if your temp_name table had multiple rows with different column names, you'd try to insert the corresponding values from those columns in the customers table into multiple rows in temp_new, all in the same id column, as shown in this db<>fiddle.
I guess this is the starting point for something more complicated, but still seems a little odd.

oracle stored procedure - select, update and return a random set of rows

oracle i wish to select few rows at random from a table, update a column in those rows and return them using stored procedure
PROCEDURE getrows(box IN VARCHAR2, row_no IN NUMBER, work_dtls_out OUT dtls_cursor) AS
v_id VARCHAR2(20);
v_workname VARCHAR2(20);
v_status VARCHAR2(20);
v_work_dtls_cursor dtls_cursor;
BEGIN
OPEN v_work_dtls_cursor FOR
SELECT id, workname, status
FROM item
WHERE status IS NULL
AND rownum <= row_no
FOR UPDATE;
LOOP
FETCH v_work_dtls_cursor
INTO v_id ,v_workname,v_status;
UPDATE item
SET status = 'started'
WHERE id=v_id;
EXIT
WHEN v_work_dtls_cursor % NOTFOUND;
END LOOP;
close v_work_dtls_cursor ;
/* I HAVE TO RETURN THE SAME ROWS WHICH I UPDATED NOW.
SINCE CURSOR IS LOOPED THRU, I CANT DO IT. */
END getrows;
PLEASE HELP
Following up on Sjuul Janssen's excellent recommendation:
create type get_rows_row_type as object
(id [item.id%type],
workname [item.workname%type],
status [item.status%type]
)
/
create type get_rows_tab_type as table of get_rows_row_type
/
create function get_rows (box in varchar2, row_no in number)
return get_rows_tab_type pipelined
as
v_work_dtls_cursor dtls_cursor;
l_out_rec get_rows_row_type;
BEGIN
OPEN v_work_dtls_cursor FOR
SELECT id, workname, status
FROM item sample ([ROW SAMPLE PERCENTAGE])
WHERE status IS NULL
AND rownum <= row_no
FOR UPDATE;
LOOP
FETCH v_work_dtls_cursor
INTO l_out_rec.id, l_out_rec.workname, l_outrec.status;
EXIT WHEN v_work_dtls_cursor%NOTFOUND;
UPDATE item
SET status = 'started'
WHERE id=l_out_rec.id;
l_out_rec.id.status := 'started';
PIPE ROW (l_out_rec);
END LOOP;
close v_work_dtls_cursor ;
END;
/
A few notes:
This is untested.
You'll need to replace the bracketed section in the type declarations with appropriate types for your schema.
You'll need to come up with an appropriate value in the SAMPLE clause of the SELECT statement; it might be possible to pass that in as an argument, but that may require using dynamic SQL. However, if your requirement is to get random rows from the table -- which just filtering by ROWNUM will not accomplish -- you'll want to do something like this.
Because you're SELECTing FOR UPDATE, one session can block another. If you're in 11g, you may wish to examine the SKIP LOCKED clause of the SELECT statement, which will enable multiple concurrent sessions to run code like this.
Not sure where you are doing your committing, but based on the code as it stands all you should need to do is SELECT ... FROM ITEM WHERE STATUS='started'
If it is small numbers, you could keep a collection of ROWIDs.
if it is larger, then I'd do an
INSERT into a global temporary table SELECT id FROM item .. AND ROWNUM < n;
UPDATE item SET status = .. WHERE id in (SELECT id FROM global_temp_table);
Then return a cursor of
SELECT ... FROM item WHERE id in (SELECT id FROM global_temp_table);
Maybe this can help you to do what you want?
http://it.toolbox.com/blogs/database-solutions/returning-rows-through-a-table-function-in-oracle-7802
A possible solution:
create type nt_number as table of number;
PROCEDURE getrows(box IN VARCHAR2,
row_no IN NUMBER,
work_dtls_out OUT dtls_cursor) AS
v_item_rows nt_number;
indx number;
cursor cur_work_dtls_cursor is
SELECT id
FROM item
WHERE status IS NULL
AND rownum <= row_no
FOR UPDATE;
BEGIN
open cur_work_dtls_cursor;
fetch cur_work_dtls_cursor bulk collect into nt_number;
for indx in 1 .. item_rows.count loop
UPDATE item
SET status = 'started'
WHERE id=v_item_rows(indx);
END LOOP;
close cur_work_dtls_cursor;
open work_dtls_out for select id, workname, status
from item i, table(v_item_rows) t
where i.id = t.column_value;
END getrows;
If the number of rows is particularly large, the global temporary solution may be better.

Resources