I'm using Oracle APEX 5.0 and I'm trying to built a classic report with custom search based on more than one criteria like (From Date, To Date, Serial And Emp Name(Selected from List and returns ID)), I wrote the Conditions Like :
where emp_id = nvl(:P73_EMP_ID,emp_id)
or ror_serial like nvl('%'||:P73_SERIAL||'%',ror_serial)`
or ror_effective_date between to_date(:P73_FROM_DATE) and to_date(:P73_TO_DATE)
and ror_approved_flag = 'N'
The problem is that I need The search based on one or more Criteria, That means I may left some items empty, and if all the items are empty, I need the whole records to be shown, Thanks For help.
There are two ways to do this:
1. "Quick and Dirty" way
This is fine as long as you are dealing with small data sets where performance will not be an issue.
Simply allow for nulls in your conditions e.g.
and (:P73_FROM_DATE is null or ror_effective_date >= to_date(:P73_FROM_DATE))
and (:P73_FROM_DATE is null or ror_effective_date <= to_date(:P73_TO_DATE))
and so on.
2. Dynamic SQL
This is better for larger data sets where performance could be an issue.
Change the report source type to "PL/SQL function returning SQL query".
Then change the source to look like this
declare
q long;
begin
-- The query with any conditions always applied
q := 'select a, b, c from mytable where ror_approved_flag = ''N''';
-- Append any optional conditions
if :P73_FROM_DATE is not null then
q := q || ' and ror_effective_date >= to_date(:P73_FROM_DATE)';
end if;
-- etc.
return q;
end;
This will result in an appropriate query being generated based on the criteria you have. This means that Oracle can choose the most appropriate query plan for the criteria.
Interactive report can be the way. You can filter and use multiple filters. You can save reports too. It meets all your requirements with minimal sql knowledge.
Don't know how complicated your query can bee but if you need to change syntax of your query then only way is prepare statement with some pl/sql logic.
Also look at sample apps like P-Track in APEX page 35 - Milestones it can give you some ideas to prepare the rest.
Related
I'm running Apex 19.2 and I would like to create a classical or interactive report based on dynamic query.
The query I'm using is not known at design time. It depends on an page item value.
-- So I have a function that generates the SQL as follows
GetSQLQuery(:P1_MyItem);
This function may return something like
select Field1 from Table1
or
Select field1,field2 from Table1 inner join Table2 on ...
So it's not a sql query always with the same number of columns. It's completely variable.
I tried using PL/SQL function Body returning SQL Query but it seems like Apex needs to parse the query at design time.
Has anyone an idea how to solve that please ?
Cheers,
Thanks.
Enable the Use Generic Column Names option, as Koen said.
Then set Generic Column Count to the upper bound of the number of columns the query might return.
If you need dynamic column headers too, go to the region attributes and set Type (under Heading) to the appropriate value. PL/SQL Function Body is the most flexible and powerful option, but it's also the most work. Just make sure you return the correct number of headings as per the query.
How can I use a plsql code block like this with an Interactive Grid (Using Oracle Apex) :
begin
Query A;
exception when no_data_found then
Query B;
end;
Actually sometimes 'Query A' returns nothing and I want to run 'Query B'. any solution?
An interactive grid has to use a sql-query as source.
a. Write one query and use sql-query as source:
SELECT * FROM A
UNION ALL
SELECT * FROM B WHERE COUNT(SELECT * FROM A) = 0;
b. Write some function which does the work
Read this:
How to return a resultset / cursor from a Oracle PL/SQL anonymous block that executes Dynamic SQL?
But it sounds a little bit strange, that you got one grid for two datasources. This will bring up some problems when manipulating the data.
Open questions
Do you want to modify the data?
Do you want to insert new rows?
Does the user understand what's going on and what he is seeing?
Since there is no apparent way to NOT use an SQL query as the Interactive Grid source, you could maybe (depending on your specific solution) think differently and create an Interactive Grid region for each query. Then you could show one or another when the page loads, using a region server-side condition or even a Dynamic Action.
To expand on other answers with a little specificity, since this is about managing results of 2 different queries, you can put the 2 different queries in 2 different Grid regions. Then on the first region add a Server-side Condition of "Rows returned" and copy the SQL Query into the query input provided. On the 2nd region, you would set "No Rows returned" condition and again copy Query 1 into the SQL input provided.
I need to recreate some SAP stored procedures in Oracle. I've been trying to find tutorials, similar questions, examples, etc about this but apparently no one had to do this before
What Oracle SQL query can be similar to this SAP query ?
SELECT * FROM A
INTO CORRESPONDING FIELDS OF TABLE B
FOR ALL ENTRIES IN C
WHERE a = C-a
AND x = y.
LOOP AT B INTO D.
D-b = E-b.
INSERT c FROM D.
IF SY-SUBRC <> 0.
WRITE: / 'error on insert', D-b, D-a.
ENDIF.
Any help will be appreciated, Thanks.
I recommend you to use transaction 'ST05' to trace your program. This tool will show details of the queries on the database including the exact SQL executed.
EDIT:
As a demonstration of the queries generated by SAP for Oracle let's execute this code and trace it with transaction 'ST05'. Remember to run 'ST05' before executing the program.
tables: mara.
data: it_mara type standard table of mara,
it_eina type standard table of eina.
select-options so_matnr for mara-matnr.
start-of-selection.
select matnr from mara into corresponding fields of table it_mara
up to 100 rows where matnr in so_matnr.
check sy-subrc eq 0.
select * from eina into table it_eina for all entries in it_mara
where matnr eq it_mara-matnr.
After execution check the output in transaction 'ST05':
If you want more details select an SQL statement in the screen and then click the button 'Explain'. You will see the following:
For better reference on transaction 'ST05' check this link.
Hope it helps.
The FOR ALL ENTRIES statement usually produces many queries which results are then grouped by UNION or UNION ALL.
Here is a really nice analysis for Microsoft SQL Server.
Because of the fact that UNION and UNION ALL are part of SQL standard I think it is implemented exactly the same for any other SQL database.
[EDIT]
As Mr Miranda stated it looks differently when it comes to Oracle database. I googled a bit and found this article where it is said that IN-LISTs are used which seems also to be plausible.
I have a query, something like
select * from table1 where :iparam is null or iparam = field1;
On field1 there is a non-unique index, but oracle (11g) don't want to use it. As i understand, it optimize query not in run-time, but at compiling. I'm using such query in stored procedures. I wonder, if there is a way, to tell oracle, to use an indexes?
I know about "hints" but i would like to use something on all project, like some optimizer argument, to optimize queries in run-time.
where :iparam is null or :iparam = field1;
Oracle has no way of knowing in advance if you will pass NULL value for :iparam
If you do, full scan is the best way to access data. If you don't, index might be better. You can split this statement in two parts using IF, then there will be no ambiguity.
If you have a lot of fields to compare, dynamic sql migh be a better way.
IF :param1 IS NOT NULL THEN
v_sql := v_sql||' and field1 = :param1';
ELSE
v_sql := v_sql||' and nvl(:param1,1) = 1';
END IF;
ELSE part is for easyer usage of USING.
It is not true that the execution plan is determined at the time of package compilation. It will be determined just before the query is actually executed.
How the optimizer decides to run the query depends on many things. Foremost the availability of statistics. These give the optimizer something to go on. How many records are in the table. How many different values are in the index.
Here is an article that goes into more detail:
http://joco.name/2014/01/05/why-wouldnt-oracle-use-a-perfectly-valid-index/
I'm writting some stored functions in Oracle. One of these is a really basic function who take a string as parameter and return an another string. Here is my function:
CREATE OR REPLACE
FUNCTION get_mail_custcode (
custcodeParam IN customer_table.custcode%TYPE)
RETURN VARCHAR2
IS
mail_rc contact_table.email%TYPE;
BEGIN
SELECT cc.email
INTO mail_rc
FROM contact_table cc, customer_table cu
WHERE cu.customer_id = cc.customer_id
AND cu.custcode like custcodeParam ;
RETURN mail_rc ;
END;
So it's not working.. The function seems to work well but is executed without any end.. The function is working time and time, I manually cancel the operation after 2 or 3 minutes (this query give normally instant result).
After writing the query again and again I finally (and randomly) change the cu.custcode like custcodeParam into a cu.custcode = custcodeParam and it is working!!
So my question is why? Why I can't use a like comparator in a stored function? Why this makes no error but the function run indefinitly.
Thanks.
Cursors are all treated identically in Oracle. A query in a function will be treated exactly the same as a query you enter manually through SQL*Plus.
However, what may differ in your example is how Oracle works with variables. The following two queries are fundamentally different to the optimizer:
SELECT * FROM tab WHERE code LIKE 'FOO%';
and
variable v_code VARCHAR2(4)
EXEC :v_code := 'FOO%';
SELECT * FROM tab WHERE code LIKE :v_code;
In the first case the optimizer looks at the constant FOO% and can instantly tell that an index on code is perfectly suited to retrieve the rows rapidly via an index RANGE SCAN.
In the second case, the optimizer has to consider that :V_CODE is not constant. The purpose of the optimizer is to determine a plan for a query that will be shared by successive executions of the same query (because computing a plan is expensive).
The behaviour of the optimizer will depend upon your version of Oracle:
In old Oracle versions (9i and before), the value of the variable was ignored to build the plan. In effect Oracle had to build a plan that would be efficiently, whatever value was passed to it. In your case this likely would result in a full scan because Oracle had to take the least risky option and consider that FOO% was as likely a value as %FOO (the latter can't be accessed efficiently via an index range scan).
In 10g Oracle introduced bind peeking: now the optimizer can access the value of the variable and produce a suitable plan. The main problem is that in most cases a query can only have one plan, which means that the value of the first variable ever passed to the function will force the execution plan for all further executions. If the first value to be passed is %FOO, a FULL SCAN will likely be chosen.
In 11g, Oracle has "intelligent cursor sharing": a single query can share more than one plan, in the example above the value FOO% would use a RANGE SCAN while %FOO would probably use a FULL SCAN.
What version of Oracle are you using?
update
In 10g and before if this function is used often without wildcards you should rewrite it to acknowledge the optimizer behaviour:
BEGIN
IF instr(custcodeParam, '%') > 0 OR instr(custcodeParam, '_') > 0 THEN
SELECT cc.email
INTO mail_rc
FROM contact_table cc, customer_table cu
WHERE cu.customer_id = cc.customer_id
AND cu.custcode LIKE custcodeParam;
ELSE
SELECT cc.email
INTO mail_rc
FROM contact_table cc, customer_table cu
WHERE cu.customer_id = cc.customer_id
AND cu.custcode = custcodeParam;
END IF;
RETURN mail_rc;
END;