It's possible to get a Oracle APEX 5 item value inside SQL Developer ?
I know it'possible to use something like that:
SELECT *
FROM apex_050100.wwv_flow_data d
inner join apex_050100.wwv_flow_sessions$ s on d.flow_instance = s.id;
where d.flow_instance = <session_id_from_url>;
But i want to use the V function:
select v('ITEM') FROM DUAL;
Or event better to set this item value like this:
APEX_UTIL.SET_SESSION_STATE (
p_name IN VARCHAR2 DEFAULT NULL,
p_value IN VARCHAR2 DEFAULT NULL);
You should use bind variables instead of the v function. Rather than this:
select *
from table
where column = v('PX_ITEM_NAME');
Do this instead:
select *
from table
where column = :PX_ITEM_NAME;
This is safer (not vulnerable to SQL injection), more performant (avoids hard parses and uses shared cursors), and more convenient in that you can copy this over to SQL Developer.
When you run this in SQL Developer, you will be prompted for the values before the query is executed.
Related
Is there a hint to generate execution plan ignoring the existing one from the shared pool?
There is not a hint to create an execution plan that ignores plans in the shared pool. A more common way of phrasing this question is: how do I get Oracle to always perform a hard parse?
There are a few weird situations where this behavior is required. It would be helpful to fully explain your reason for needing this, as the solution varies depending why you need it.
Strange performance problem. Oracle performs some dynamic re-optimization of SQL statements after the first run, like adaptive cursor sharing and cardinality feedback. In the rare case when those features backfire you might want to disable them.
Dynamic query. You have a dynamic query that used Oracle data cartridge to fetch data in the parse step, but Oracle won't execute the parse step because the query looks static to Oracle.
Misunderstanding. Something has gone wrong and this is an XY problem.
Solutions
The simplest way to solve this problem are by using Thorsten Kettner's solution of changing the query each time.
If that's not an option, the second simplest solution is to flush the query from the shared pool, like this:
--This only works one node at a time.
begin
for statements in
(
select distinct address, hash_value
from gv$sql
where sql_id = '33t9pk44udr4x'
order by 1,2
) loop
sys.dbms_shared_pool.purge(statements.address||','||statements.hash_value, 'C');
end loop;
end;
/
If you have no control over the SQL, and need to fix the problem using a side-effect style solution, Jonathan Lewis and Randolf Geist have a solution using Virtual Private Database, that adds a unique predicate to each SQL statement on a specific table. You asked for something weird, here's a weird solution. Buckle up.
-- Create a random predicate for each query on a specific table.
create table hard_parse_test_rand as
select * from all_objects
where rownum <= 1000;
begin
dbms_stats.gather_table_stats(null, 'hard_parse_test_rand');
end;
/
create or replace package pkg_rls_force_hard_parse_rand is
function force_hard_parse (in_schema varchar2, in_object varchar2) return varchar2;
end pkg_rls_force_hard_parse_rand;
/
create or replace package body pkg_rls_force_hard_parse_rand is
function force_hard_parse (in_schema varchar2, in_object varchar2) return varchar2
is
s_predicate varchar2(100);
n_random pls_integer;
begin
n_random := round(dbms_random.value(1, 1000000));
-- s_predicate := '1 = 1';
s_predicate := to_char(n_random, 'TM') || ' = ' || to_char(n_random, 'TM');
-- s_predicate := 'object_type = ''TABLE''';
return s_predicate;
end force_hard_parse;
end pkg_rls_force_hard_parse_rand;
/
begin
DBMS_RLS.ADD_POLICY (USER, 'hard_parse_test_rand', 'hard_parse_policy', USER, 'pkg_rls_force_hard_parse_rand.force_hard_parse', 'select');
end;
/
alter system flush shared_pool;
You can see the hard-parsing in action by running the same query multiple times:
select * from hard_parse_test_rand;
select * from hard_parse_test_rand;
select * from hard_parse_test_rand;
select * from hard_parse_test_rand;
Now there are three entries in GV$SQL for each execution. There's some odd behavior in Virtual Private Database that parses the query multiple times, even though the final text looks the same.
select *
from gv$sql
where sql_text like '%hard_parse_test_rand%'
and sql_text not like '%quine%'
order by 1;
I think there is no hint indicating that Oracle shall find a new execution plan everytime it runs the query.
This is something we'd want for select * from mytable where is_active = :active, with is_active being 1 for very few rows and 0 for maybe billions of other rows. We'd want an index access for :active = 1 and a full table scan for :active = 0 then. Two different plans.
As far as I know, Oracle uses bind variable peeking in later versions, so with a look at the statistics it really comes up with different execution plans for different bind varibale content. But in older versions it did not, and thus we'd want some hint saying "make a new plan" there.
Oracle only re-used an execution plan for exactly the same query. It sufficed to add a mere blank to get a new plan. Hence a solution might be to generate the query everytime you want to run it with a random number included in a comment:
select /* 1234567 */ * from mytable where is_active = :active;
Or just don't use bind variables, if this is the problem you want to address:
select * from mytable where is_active = 0;
select * from mytable where is_active = 1;
I am currently using apex 19.1. I have this problem where I can't (or don't know how to) select certain columns from checkbox meaning I have this checkbox
which gives me the ability to check the columns names I want to use that output (:P3_COLUMN) from the check box to select a specific columns in a table. My solution was :
select :P3_COLUMN
from INPUT_TABLE$
I also tried :
select case :P3_COLUMN when 'currency' then currency when 'nationality' then nationality end as test from input_table
which gave me this output
and
DECLARE
str varchar2(100);
BEGIN
str := 'select ' || replace(:P3_COLUMN, ':', ',') || ' from input_table';
execute immediate str;
END;
which gave me this error
I don't know what to do, any help will be really appreciated.
Here's a walkthrough (my page is #51). Suppose that we want to display some column from Scott's DEPT table.
create a region whose type is classic report
create a page item (let's call it P51_COLS which is a select list item; its source is a query which looks like this:
select column_name d,
column_name r
from user_Tab_columns
where table_name = 'DEPT'
Page action on selection should be "Submit page"
region's source should be a PL/SQL function body that returns a SQL query and look like this:
return 'select case when :P51_COLS = ''DEPTNO'' then to_char(deptno )
when :P51_COLS = ''DNAME'' then dname
when :P51_COLS = ''LOC'' then loc
end as result
from dept';
Its "Page items to submit" should be set to P51_COLS
That's it ... run the page; select any column from the select list item and the result should be displayed.
Yes, I know - the query itself looks stupid as you have to name all cases. For some reason, Apex expects literally return 'select ...' statement. Concatenation, replace function, ... won't work. Perhaps someone knows why or - even better - can demonstrate how to workaround it. Meanwhile, try what's been written above.
first option use server side condition on the columns.
second option use dynamic sql> create function returns sql statement> call the function in your region source.
I've written a stored procedure that updates a table.
But I would like to take into account where one or more of the parameters are NULL.
In such an instance, I don't want to update the column, I want to leave the existing value as is.
I've tried to use:
UPDATE
VS_USER_T
SET
USR_FIRST_NAME = ISNULL(p_NewUsrFName, #p_NewUsrFName)
WHERE
USR_ID = lv_Num_UsrId;
But I get an error on the '#', I'm using Oracle 12c.
This is the procedure call
PROCEDURE UpdateUser
( p_UserId IN VS_USER_T.USR_ID%TYPE,
p_NewUsrFName IN VS_USER_T.USR_FIRST_NAME%TYPE,
p_NewUsrLName IN VS_USER_T.USR_LAST_NAME%TYPE,
p_NewUsrname IN VS_USER_T.USR_LOGIN%TYPE)
Please advise how my UPDATE statement should look like, when 'p_NewUsrname ' can be NULL, in which case I want to leave the existing value as is.
Thanks in advance.
To keep the existing value you need to refer to the existing column value:
USR_FIRST_NAME = ISNULL(p_NewUsrFName, USER_FIRST_NAME)
or you could use:
USR_FIRST_NAME = CASE WHEN p_NewUsrFName is null THEN USER_FIRST_NAME ELSE NewUsrFName END
ISNULL() is not yet a standard Oracle function (at least in the Oracle 12c version that you say you are using). If is of course possible to write a PL/SQL function called ISNULL() and use that.
For a standard Oracle 12c installation, try using NVL or COALESCE instead.
USR_FIRST_NAME = NVL(p_NewUsrFName, USR_FIRST_NAME)
or
USR_FIRST_NAME = COALESCE(p_NewUsrFName, USR_FIRST_NAME)
You could use a decode statement e.g.
update my_table t
set username = decode(p_NewUsrname, NULL, t.username, p_NewUsrname)
where t.id = p_UserId;
I have a problem which I can't solve. Maybe you have an idea about how to solve it.
I do have a given parameter-table like this:
P_VALUE P_NAME
----------- ----------
X85 A_03
XH1 A_04
XH2 A_04
XH3 A_04
C84 A_05
As you can see there are parameters with multiple entries. At the moment this parameters are used in this way:
SELECT * FROM tablex
WHERE code IN (SELECT p_value
FROM parameter_table
WHERE p_name LIKE 'A_04');
As the query is very big these parameter sub-select are used very often. I was trying to implement a function in Oracle to get my parameters. This works very fine as long as there is just 1 row per parameter. When I want to use it in "IN-Statements", it won't work because functions just return a single value.
--WORKS
SELECT * FROM tablex
WHERE code = (f_get_param('A_03'));
--DOES NOT WORK
SELECT * FROM tablex
WHERE code IN (f_get_param('A_04'));
Please note that I need it for plain SQL statements, so procedures won't work as they are just good for PL/SQL.
I would be really thankful for good ideas or help!
Use collections. Here you have an example http://www.adp-gmbh.ch/ora/plsql/coll/return_table.html
Technically you can achieve using the function this way but doing this will cause index not to be used on code column on tablex and may affect performance .Using function index you can reduce performance impact
CREATE OR REPLACE FUNCTION f_get_param(p_value1 IN VARCHAR2,p_name1 in VARCHAR2) return NUMBER
DETERMINISTIC
IS
l_count NUMBER;
BEGIN
select count(1) into l_count from parameter_table where p_value =p_value1
and p_name=p_name1;
if l_count > 0
then
return 1;
else
return 0;
end if;
end f_get_param;
AND use the select statement like this
SELECT * FROM tablex
WHERE f_get_param(code,'A_04')=1;
EDIT 1:-
Also to reduce the performance impact in database 10.2 and greater If the parameter_table is static you can use the DETERMINISTIC clause in the Function to say that the function returns the same value if called with same parameters every time
Please find the link on the article about using functions in SELECT statement
--DOES NOT WORK
SELECT * FROM tablex
WHERE code IN (f_get_param('A_04'));
-- Try this
SELECT * FROM tablex
WHERE code IN (select * from TABLE(f_get_param('A_04')));
You have to "CAST" a collection onto SQL TABLE.
Also when you use cast you can also use inner joint:
SELECT * FROM tablex join TABLE(f_get_param('A_04') using (code);
I think - generally - your problem is called "Dynamic where clause". Try to search some articles about it on AskTom.
I think the actual solution to your problem is to simply join the two tables and create the appropriate indexes rather than invoking a PL/SQL function at all:
SELECT x.* FROM tablex x, parameter_table p
WHERE x.code = p.p_value
AND p.p_name LIKE '%A_04%';
Note that you also have a semantic error in your LIKE clause. You're not using the % sign therefore your LIKE 'A_04' is just the same as = 'A_04'
I've got an association table that groups accounts together.
I'm trying to select a subset of table 'target'
p_group_id := 7;
select *
target t
where t.account_id in get_account_ids(p_group_id);
Is it possible to write a function that returns a list of account_ids (as some form of collection) that would facilitate the above code?
I've looked at pipelined functions, however I want to stay away from loops and cursors. Also, custom types / table also get into casting that I'd like to avoid.
For reference, here's some pseudocode for what the function 'get_account_ids' would do, hypothetically:
function get_account_ids(p_group_id)
insert into v_ret
select aa.account_id
from assoc_account aa
where aa.groupid = p_group_id;
return v_ret;
You simply need:
select *
from target t
where t.account_id in
( select aa.account_id
from assoc_account aa
where aa.groupid = 7;
)
The above will work, assuming that assoc_account.account_id is never NULL.