Select Query With Variable - oracle

I'm working withing Oracle 6i Form
the form is search form , it has many text items for criteria search
and there is command button
when pressed , the form will show all records
is user selected some items in creteria text items , the result will be filtered
based on those creteria
now this is done , and then I want to export the result to a text file using the following code
OUTFILE TEXT_IO.FILE_TYPE;
filename varchar2(100);
sql_string varchar2(8000);
a number(10);
begin
a := 0;
if :norm.Dob_fr is not null and :norm.Dob_to is not null then
sql_string := sql_string || ' (DATE_FROM >= to_date(''' || to_char(:norm.Dob_fr,'YYYY-MM-DD') || ''',''YYYY-MM-DD'') and date_to <= to_date(''' || to_char(:norm.Dob_to,'YYYY-MM-DD') || ''',''YYYY-MM-DD'')';
a := 1;
end if;
if :norm.per_fr is not null and :norm.per_to is not null then
if a = 1 then
sql_where := ' and ';
else
sql_where := ' ( ';
a := 1;
end if;
sql_string := sql_string || sql_where || ' pay_date >= to_date(''' || to_char(:norm.per_fr,'YYYY-MM-DD') || ''',''YYYY-MM-DD'') and pay_date <= to_date(''' || to_char(:norm.per_to,'YYYY-MM-DD') || ''',''YYYY-MM-DD'')';
end if;
sql_string := sql_string || ' ) ';
FOR SE IN ('select * from V_BILL_TRAN where ' || nvl(sql_string,'1=1') loop
the export code is working well , but my issue is in the last statement shown above , the where statement "sql_string: it may or not contain a data
then the code is not accepted by oracle form 6i
there is something wrong

This is wrong:
sql_string := sql_string || ' ) ';
The closing bracket causes problems because - even if there's nothing in sql_string, after concatenating the bracket, sql_string will become ) and it'll cause problems in the next statement (FOR loop) as nvl(sql_string, 1=1) won't take effect - the result will be
select * from V_BILL_TRAN where )
instead of
select * from V_BILL_TRAN where 1=1
Rewrite it to
sql_string := sql_string || case when sql_string is not null then ')' end;

this is the initial code
OUTFILE TEXT_IO.FILE_TYPE;
filename varchar2(100);
sql_string varchar2(8000);
a number(10);
begin
a := 0;
if :norm.Dob_fr is not null and :norm.Dob_to is not null then
sql_string := sql_string || ' (DATE_FROM >= to_date(''' || to_char(:norm.Dob_fr,'YYYY-MM-DD') || ''',''YYYY-MM-DD'') and date_to <= to_date(''' || to_char(:norm.Dob_to,'YYYY-MM-DD') || ''',''YYYY-MM-DD'')';
a := 1;
end if;
if :norm.per_fr is not null and :norm.per_to is not null then
if a = 1 then
sql_where := ' and ';
else
sql_where := ' ( ';
a := 1;
end if;
sql_string := sql_string || sql_where || ' pay_date >= to_date(''' || to_char(:norm.per_fr,'YYYY-MM-DD') || ''',''YYYY-MM-DD'') and pay_date <= to_date(''' || to_char(:norm.per_to,'YYYY-MM-DD') || ''',''YYYY-MM-DD'')';
end if;
sql_string := sql_string || ' ) ';
FOR SE IN ('select * from V_BILL_TRAN where ' || nvl(sql_string,'1=1') loop

Related

“ORA-00907: missing right parenthesis” using insrt function with PLSQL

I wrote this code using a portion of query in a string. Inside the string I'm using INSTR FUNCTION to split a multi value selection. Anyway, when I run this code I'm keeping to get the error message:"“ORA-00907: missing right parenthesis”
sql_1 varchar2(4000);
sql_2 varchar2(4000);
year varchar2(100);
sql_1:='select count(*) ';
year:='2019:2020';
sql_view_column:='v_cod_device';
type_selection:='03L20';
if selection= 'M' then
sql_2:=sql_2||'MONTH ';
sql_2:=sql_2||'where '||sql_view_column||' = '''||type_selection||''' and instr( '':'' '''||year||''' '':'' , '':'' v_year '':'' ) >0 ';
end if;
command_sql:=sql_1||sql_2;
EXECUTE IMMEDIATE command_sql
INTO counter;
When my code runs the execute immediate comand_sql statement, I will get the exception.
You need to replace
sql_1 := 'select count(*) ';
with
sql_1 := 'select count(*) FROM '; -- added FROM here
and
sql_2:=sql_2||'where '||sql_view_column||' = '''||type_selection||''' and instr( '':'' '''||year||''' '':'' , '':'' v_year '':'' ) >0 ';
with
sql_2:=sql_2|| 'where '|| sql_view_column ||' = '''|| type_selection ||''' and instr( '':'' || '''|| year ||''' || '':'' , '':'' || v_year || '':'' ) >0 ' ;
Note: in the above string, You have not used proper single quotes which are corrected in replace string. Also, Your code will not work if the condition if selection= 'M' then is false. You need to handle it correctly.
If you put your code into an anonymous block, and change the EXECUTE IMMEDIATE into a DBMS_OUTPUT.PUT_LINE to test it out, this is what you get:
select count(*) MONTH
where v_cod_device = '03L20'
and instr( ':' '2019:2020' ':' , ':' v_year ':' ) >0
You can see there is no FROM and the instr() syntax is wrong. Here is the anonymous block that I used to troubleshoot this:
DECLARE
sql_1 VARCHAR2 (4000);
sql_2 VARCHAR2 (4000);
year VARCHAR2 (100);
sql_view_column VARCHAR2 (100);
type_selection VARCHAR2 (100);
selection VARCHAR2 (100) := 'M';
command_sql VARCHAR2 (8000);
counter NUMBER;
BEGIN
sql_1 := 'select count(*) ';
year := '2019:2020';
sql_view_column := 'v_cod_device';
type_selection := '03L20';
IF selection = 'M' THEN
sql_2 := sql_2 || 'MONTH ';
sql_2 := sql_2 || 'where ' || sql_view_column || ' = ''' || type_selection || ''' and instr( '':'' ''' || year || ''' '':'' , '':'' v_year '':'' ) >0 ';
END IF;
command_sql := sql_1 || sql_2;
DBMS_OUTPUT.put_line (command_sql);
--EXECUTE IMMEDIATE command_sql INTO counter;
END;
Not having any idea what you want to accomplish, I might make a random guess that you are trying to do something like this?
IF selection = 'M' THEN
sql_2 := sql_2 || 'from MONTH ';
sql_2 := sql_2 || 'where ' || sql_view_column || ' = ''' || type_selection || ''' ';
IF instr(year, ':') > 0 THEN
sql_2 := sql_2
|| ' and year between ' || substr(year, 0, instr(year, ':')-1) || ' and ' || substr(year, instr(year, ':')+1);
ELSE
sql_2 := sql_2
|| ' and year = ' || year;
END IF;
END IF;
...which would result in:
select count(*)
from MONTH
where v_cod_device = '03L20' and year between 2019 and 2020

Oracle PLSQL invalid cursor error I don't understand

I'm still a relatively newbe when it comes to PL/SQL.
Using Oracle 12c on Linux RHEL 6.8, the following shell script will attempt to activate all RI constraints in a collection of tables, and if they fail with parent key failures, it will dump the first 100 rows (or less) of the offending data. Or at least that is the goal. Since the script deals mostly with system tables on 12c (with only a small user table list that is unique to my installation), I'm including the whole thing exactly from my environment.
The main work occurs in the exception handling where the system tables are queried for the constraint, and user queries are formed from those data.
As a extra goal, the output is rather messy and I want to clean it up, but first it has to work :)
The output / error I get for my tables is the following:
ERROR Handling here for table NRNG_MTC_VST Constraint Name:
SYS_C0011790 Final SQL = SELECT DISTINCT NRNG_MTC_VST.LOG_CRT_DT ,
NRNG_MTC_VST.NRRNG_MTC_LG_ID FROM ODB_PRIMARY.NRNG_MTC_VST WHERE NOT
EXISTS (SELECT 1 FROM ODB_PRIMARY.NRNG_MTC_LOG WHERE
NRNG_MTC_VST.LOG_CRT_DT = NRNG_MTC_LOG.LOG_CRT_DT AND
NRNG_MTC_VST.NRRNG_MTC_LG_ID = NRNG_MTC_LOG.NRRNG_MTC_LG_ID) FETCH
FIRST 100 rows only
---xxx End SQL DECLARE
* ERROR at line 1: ORA-01001: invalid cursor ORA-06512: at line 111 ORA-02298: cannot validate (ODB_PRIMARY.SYS_C0011790) - parent keys
not found
The output SQL from my print_line is correct, and would work if pasted directly into a SQLDeveloper session. There is just something silly about how the cursor is defined I don't understand.
The full text of the script. BYW, if you see other bonehead changes that should be made unrelated to the error, please suggest them as well.
cd $OGGHOME/scripts
export ORACLE_SID=odbod07 $ORACLE_HOME/bin/sqlplus <<-EOF / as sysdba
alter session set container=p01_odbod07;
set echo on set feedback on
set heading off
set serveroutput on size 10000
DECLARE finalsql varchar2(2048);
part1sql varchar2(1024) ;
part2sql varchar2(1024) := ' ';
cownername varchar2(1024);
ctablename varchar2(1024);
pownername varchar2(1024);
ptablename varchar2(1024);
cnt number := 0;
-- Weak cursor defs
my_cursor sys_refcursor;
BEGIN FOR i in (
select owner, table_name, constraint_name
from dba_constraints
where constraint_type = 'R'
and status = 'DISABLED'
and owner = 'ODB_PRIMARY'
and TABLE_NAME in
-- enter user tables with RI constraints here
('RRNG_MTC_STN_CPLY',
'NRNG_MTC_VST_MTRL_USG',
'NRNG_MTC_VST',
'CAR_CORE',
'NRNG_MTC_LOG'))
-- end user table definitions, rest of code should rely only on system tables
LOOP BEGIN
dbms_output.put_line('alter table '||i.owner|| '.' ||
i.table_name || ' enable constraint '||i.constraint_name);
execute immediate 'alter table '||i.owner|| '.' ||
i.table_name || ' enable constraint '||i.constraint_name;
EXCEPTION
-- exception handling - dump offending data
WHEN OTHERS THEN -- take all exceptions for now
dbms_output.put_line ('ERROR Handling here for table ' ||
i.table_name || ' Constraint Name: ' ||i.constraint_name);
finalsql := 'SELECT DISTINCT ';
part1sql := '';
part2sql := ' ';
cnt := 0;
for constraint in (
SELECT ucc1.OWNER as childowner,
ucc1.TABLE_NAME as childtable,
ucc1.column_name as childcolumn,
ucc2.OWNER as parentowner,
ucc2.TABLE_NAME as parenttable,
ucc2.column_name as parentcolumn,
utc1.data_type as childdatatype,
utc1.data_length as childdatalen
FROM all_constraints uc ,
all_cons_columns ucc1 ,
all_cons_columns ucc2,
all_tab_columns utc1
WHERE
uc.constraint_name = ucc1.constraint_name
AND uc.r_constraint_name = ucc2.constraint_name
AND ucc1.POSITION = ucc2.POSITION
AND ucc1.table_name = utc1.table_name
AND ucc1.column_name = utc1.column_name
AND uc.constraint_type = 'R'
AND uc.constraint_name = i.constraint_name
ORDER BY ucc1.TABLE_NAME , uc.constraint_name)
loop
cownername := constraint.childowner;
ctablename := constraint.childtable;
pownername := constraint.parentowner;
ptablename := constraint.parenttable;
if cnt > 0 then
part1sql := part1sql || ' , ';
part2sql := part2sql || ' AND ';
end if;
part1sql := part1sql || constraint.childtable ||
'.'||constraint.childcolumn || ' ';
part2sql := part2sql || constraint.childtable || '.'
|| constraint.childcolumn || ' = '
|| constraint.parenttable || '.' ||
constraint.parentcolumn;
cnt := cnt + 1;
end loop;
finalsql := finalsql || part1sql ||
' FROM ' || ' ' || cownername ||
'.' || ctablename ||
' WHERE NOT EXISTS (SELECT 1 FROM ' ||
pownername || '.' || ptablename ||
' WHERE ' || part2sql || ') FETCH FIRST 100 rows only';
dbms_output.put_line ('Final SQL = ' || finalsql);
dbms_output.put_line ('---xxx End SQL');
open my_cursor for finalsql;
dbms_sql.return_result(my_cursor);
close my_cursor;
-- EXECUTE IMMEDIATE finalsql;
END;
end loop; end;
/
EOF
Many thanks for any help provided.
Brian
Just to narrow this down to a simple test case, I think this is the error you are seeing:
declare
my_cursor sys_refcursor;
begin
open my_cursor for 'select ''Hello, world'' as message from dual';
dbms_sql.return_result(my_cursor);
close my_cursor; -- << Remove this line
end;
/
ERROR at line 1:
ORA-01001: invalid cursor
ORA-06512: at line 6
This is because you attempted to close the cursor when you have already passed it to dbms_sql for processing. Remove the line with close my_cursor.
declare
my_cursor sys_refcursor;
begin
open my_cursor for 'select ''Hello, world'' as message from dual';
dbms_sql.return_result(my_cursor);
end;
/
PL/SQL procedure successfully completed.
ResultSet #1
MESSAGE
------------
Hello, world
1 row selected.
I had same kind of issue when i tried to print Ref_cursor directly. Then i created a Record type variable and then fetched field values in that variable and then i used DBMS_OUTPUT for that record type variable.
Please see if below code and scenario can help you-
set serveroutput on;
declare
v_sql varchar2(1000);
v_cursor sys_refcursor;
type myrec is record(col1 varchar2(100),col2 varchar2(1000));
rec myrec;
begin
v_sql:='select name,status from t_employee where user_id in (''C001117'',''C001122'')';
open v_cursor for v_sql;
loop
fetch v_cursor
into rec;
exit when v_cursor%notfound;
dbms_output.put_line( rec.col1||':status '||rec.col2 );
end loop;
end;
/
The following is my semi-complete script. Given a table list, it will attempt to activate the RI Constraints, and if they fail it will print out the FK data records in the child table that prevent it from being applied.
The hardest part of this project was the fact that the FKs can be any number of columns and of any type, so the print the results of the select in this case was very tricky (IMO).
Thanks for the help people provided.
cd $OGGHOME/scripts
. ./functions.sh
$ORACLE_HOME/bin/sqlplus ${ORACLE_USERID}/${ORACLE_PASSWORD}#${ORACLE_SID} << EOF
set echo on
set feedback on
set heading off
set serveroutput on size unlimit
DECLARE
finalsql varchar2(2048);
part1sql varchar2(1024) ;
part2sql varchar2(1024) := ' ';
cownername varchar2(1024);
ctablename varchar2(1024);
pownername varchar2(1024);
ptablename varchar2(1024);
cnt number := 0;
desc_tab dbms_sql.desc_tab;
col_count INTEGER;
cursor_name INTEGER;
-- Weak cursor defs
my_cursor sys_refcursor;
col1 varchar2(50);
d number;
j number;
lineout varchar2(2048);
plineout varchar2(2048);
rows number;
eCount number := 0;
BEGIN
FOR i in (
select owner, table_name, constraint_name
from dba_constraints
where constraint_type = 'R'
and status = 'DISABLED'
and owner = '$DBSCHEMA'
and TABLE_NAME in (
'RRNG_MTC_STN_CPLY',
'NRNG_MTC_VST_MTRL_USG',
'NRNG_MTC_VST',
'MTC_TSK_HRHY'))
LOOP
BEGIN
dbms_output.put_line ('.');
dbms_output.put_line ('=====================================');
dbms_output.put('alter table '||i.owner|| '.' || i.table_name || ' enable constraint '||i.constraint_name);
execute immediate 'alter table '||i.owner|| '.' || i.table_name || ' enable constraint '||i.constraint_name;
dbms_output.put_line (' ... SUCCESS');
EXCEPTION -- exception handling - dump offending data
WHEN OTHERS THEN
eCount := eCount + 1;
dbms_output.put_line (' ... FAILED. Constraint Name: ' || i.constraint_name);
finalsql := 'SELECT DISTINCT ';
part1sql := '';
part2sql := ' ';
cnt := 0;
for constraint in (
SELECT ucc1.OWNER as childowner,
ucc1.TABLE_NAME as childtable,
ucc1.column_name as childcolumn,
ucc2.OWNER as parentowner,
ucc2.TABLE_NAME as parenttable,
ucc2.column_name as parentcolumn,
utc1.data_type as childdatatype,
utc1.data_length as childdatalen
FROM all_constraints uc ,
all_cons_columns ucc1 ,
all_cons_columns ucc2,
all_tab_columns utc1
WHERE
uc.constraint_name = ucc1.constraint_name
AND uc.r_constraint_name = ucc2.constraint_name
AND ucc1.POSITION = ucc2.POSITION
AND ucc1.table_name = utc1.table_name
AND ucc1.column_name = utc1.column_name
AND uc.constraint_type = 'R'
AND uc.constraint_name = i.constraint_name
ORDER BY ucc1.TABLE_NAME ,
uc.constraint_name)
loop
cownername := constraint.childowner;
ctablename := constraint.childtable;
pownername := constraint.parentowner;
ptablename := constraint.parenttable;
if cnt > 0 then
part1sql := part1sql || ' , ';
part2sql := part2sql || ' AND ';
end if;
part1sql := part1sql || constraint.childtable || '.' || constraint.childcolumn || ' ';
part2sql := part2sql || constraint.childtable || '.' || constraint.childcolumn || ' = '
|| constraint.parenttable || '.' || constraint.parentcolumn;
cnt := cnt + 1;
end loop;
finalsql := finalsql || part1sql || ' FROM ' || ' ' || cownername || '.' || ctablename || ' WHERE NOT EXISTS (SELECT 1 FROM ' ||
pownername || '.' || ptablename || ' WHERE ' || part2sql || ') FETCH FIRST 100 rows only';
dbms_output.put_line ('Final SQL = (' || finalsql || ')');
-- dbms_output.put_line ('---xxx End SQL');
lineout := 'Child Table: ' || ctablename || '(';
plineout := 'Parent Table: ' || ptablename;
cursor_name := dbms_sql.open_cursor;
dbms_sql.PARSE (cursor_name, finalsql, DBMS_SQL.NATIVE);
d := dbms_sql.execute (cursor_name);
dbms_sql.describe_columns (cursor_name, col_count, desc_tab);
for j in 1..col_count
LOOP
DBMS_SQL.DEFINE_COLUMN (cursor_name, j, col1, 30);
lineout := lineout || desc_tab(j).col_name || ' , ';
-- plineout := plineout || constraint.parentcolumn || ' ';
-- dbms_output.put_line ('Column 1: ' || j || ' is ' || desc_tab(j).col_name || ' type '
-- || desc_tab(j).col_type);
END LOOP j;
lineout := lineout || ')';
-- plineout := plineout || ')';
dbms_output.put_line (lineout);
dbms_output.put_line (plineout);
lineout := NULL;
for j in 1..col_count
LOOP
if j > 1 then
lineout := lineout || ' ';
end if;
lineout := lineout || desc_tab(j).col_name;
END LOOP;
dbms_output.put_line (lineout);
dbms_output.put_line ('----------------------------------------');
LOOP
rows := dbms_sql.fetch_rows (cursor_name);
EXIT WHEN rows = 0;
lineout := NULL;
for j in 1..col_count
LOOP
dbms_sql.column_value (cursor_name, j, col1);
if j > 1 then
lineout := ltrim(lineout || ' ' || col1);
else
lineout := col1;
END IF;
END LOOP;
dbms_output.put_line (lineout);
END LOOP;
dbms_sql.close_cursor (cursor_name);
END;
end loop;
end;
/
EOF
your FETCH FIRST 100 rows only would seem to be out of place.
This is part of the BULK COLLECT clause in a SELECT statement in PL/SQL; as far as I know, it is not part of a SQL statement you can pass into a cursor like this
This is resulting in the cursor statement being invalid

Converting a dynamic query to use bind variables in Oracle 11g

I have a dynamic search query that I would like to convert to make use of bind variables. The dynamic portion of the of query is in the where clause, and using a series of if statements to build a string that is concatenated to the rest of the query string. That query is then used in the for clause of a openstatement, which the result set is the return parameter. I'm not really sure how to accomplish this.
Here is the stored procedure:
PROCEDURE run_search(i_unit_id IN lu_unit.fsu_id%TYPE,
i_equipment IN tbl_component.component%TYPE,
i_equipment_status IN tbl_component.equipment_status%TYPE,
i_equipment_type IN tbl_component.equipment_type%TYPE,
i_equipment_subtype IN tbl_component.equipment_sub_type%TYPE,
i_system_id IN tbl_component.system_id%TYPE,
i_association_code IN tbl_component_assc_code.assc_code%TYPE,
i_manufacturer IN lu_component_manu_model.equipment_manufacturer%TYPE,
i_manumodel IN lu_component_manu_model.equipment_model%TYPE,
o_results OUT sys_refcursor) AS
v_query VARCHAR2(32767) := '';
v_where VARCHAR2(32767) := ' 1= 1';
BEGIN
IF i_unit_id IS NOT NULL THEN
v_where := v_where || ' AND unit_id=''' || i_unit_id ||''' ';
END IF;
IF i_equipment IS NOT NULL THEN
v_where := v_where || ' AND lower(component) LIKE ''%' || lower(i_equipment) ||'%'' ';
END IF;
IF i_equipment_status IS NOT NULL THEN
v_where := v_where || ' AND equipment_status=''' || i_equipment_status ||''' ';
END IF;
IF i_equipment_type IS NOT NULL THEN
v_where := v_where || ' AND equipment_type=''' || i_equipment_type ||''' ';
END IF;
IF i_equipment_subtype IS NOT NULL THEN
v_where := v_where || ' AND equipment_sub_type=''' || i_equipment_subtype ||''' ';
END IF;
IF i_system_id IS NOT NULL THEN
v_where := v_where || ' AND system_id=''' || i_system_id || ''' ';
END IF;
IF i_association_code IS NOT NULL THEN
v_where := v_where || ' AND EXISTS ( select null from tbl_component_assc_code where assc_code = ''' || i_association_code || ''' and component_id = vcs.component_id )';
END IF;
IF i_manufacturer IS NOT NULL THEN
v_where := v_where || ' AND equipment_manufacturer=''' || i_manufacturer || ''' ';
END IF;
IF i_manuModel IS NOT NULL THEN
v_where := v_where || ' AND equipment_model=''' || i_manuModel || ''' ';
END IF;
v_query :=
' SELECT rownum, results.* '
||' FROM '
||' ( SELECT '
||' count(*) OVER () ' || ' as total_results, '
||''
||' site_id, site_display_name, '
||' unit_id, unit_display_name, '
||' system_id, system_display_name, '
||' component_id, component, component_description, equipment_description, '
||' equipment_status, equipment_model, equipment_serial_number, equipment_type, equipment_sub_type, '
||' template_ids '
||''
||' FROM vw_component_search '
||' WHERE ' || v_where
||' ORDER BY unit_display_name, component '
||' ) results '
;
OPEN o_results FOR v_query;
END run_search;
You can write the query without dynamically creating it so you include all the parameters and just ignore those which are NULL (please profile it to test whether there are any performance issues compared to a dynamic query):
PROCEDURE run_search(i_unit_id IN lu_unit.fsu_id%TYPE,
i_equipment IN tbl_component.component%TYPE,
i_equipment_status IN tbl_component.equipment_status%TYPE,
i_equipment_type IN tbl_component.equipment_type%TYPE,
i_equipment_subtype IN tbl_component.equipment_sub_type%TYPE,
i_system_id IN tbl_component.system_id%TYPE,
i_association_code IN tbl_component_assc_code.assc_code%TYPE,
i_manufacturer IN lu_component_manu_model.equipment_manufacturer%TYPE,
i_manumodel IN lu_component_manu_model.equipment_model%TYPE,
o_results OUT sys_refcursor)
AS
BEGIN
OPEN o_results FOR
SELECT rownum,
results.*
FROM ( SELECT count(*) OVER () as total_results,
site_id,
site_display_name,
unit_id,
unit_display_name,
system_id,
system_display_name,
component_id,
component,
component_description,
equipment_description,
equipment_status,
equipment_model,
equipment_serial_number,
equipment_type,
equipment_sub_type,
template_ids
FROM vw_component_search
WHERE ( i_unit_id IS NULL
OR unit_id= i_unit_id )
AND ( i_equipment IS NULL
OR lower(component) LIKE '%' || lower(i_equipment) || '%' )
AND ( i_equipment_status IS NULL
OR equipment_status= i_equipment_status )
AND ( i_equipment_type IS NULL
OR equipment_type= i_equipment_type )
AND ( i_equipment_subtype IS NULL
OR equipment_sub_type= i_equipment_subtype )
AND ( i_system_id IS NULL
OR system_id= i_system_id )
AND ( i_association_code IS NULL
OR EXISTS ( select null
from tbl_component_assc_code
where assc_code = i_association_code
and component_id = vcs.component_id ) )
AND ( i_manufacturer IS NULL
OR equipment_manufacturer= i_manufacturer )
AND ( i_manuModel IS NULL
OR equipment_model= i_manuModel )
ORDER BY unit_display_name, component
) results;
END run_search;
(I've not compiled the above code - so there may be some errors).
The best way is to avoid such headache at all. 'SP returning resultset' is a usual practise in a poor legacy things such as MSSQL2000, but in unnecessary and doubtful in Oracle.
If you wish to do this, I'd advice you to do something like this:
procedure MakeGarbage(value_mask varchar2) return sys_refcursor is
cur integer;
stmt varchar2(32000 byte);
type TParamTable is table of varchar2(1000) index by varchar2(20);
params TParamTable;
i varchar2(20);
begin
stmt := 'select * from table where 1 = 1 ';
if value_mask is not null then
stmt := stmt || ' and value like :value_mask ';
params('value_mask') := value_mask;
end if;
...
cur := dbms_sql.create_cursor;
dbms_sql.open_cursor(cur, stmt, dbms_sql.native);
i := params.first;
while i is not null loop
dbms_sql.bind_variable(i, params(i));
i := params.next(i);
end loop;
return dbms_sql.to_ref_cursor(cur);
end;
every reference to a PL/SQL variable is in fact a bind variable.
you can check this asktom link
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2320123769177
and check "Dynamic SQL" from this link http://www.akadia.com/services/ora_bind_variables.html

Oracle: PLSQL query with relaxable where condition - elegant way to realize

Look at the following query. How could I write it in a more readable way?
I'd like to reduce the usage of IF
vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 ';
IF P_LOC_LOCALITA_COD IS NOT NULL THEN
vSQL := vSQL||' AND LOC.LOC_LOCALITA_COD = '''||P_LOC_LOCALITA_COD||''' ';
END IF;
IF P_ISTAT_CITTA IS NOT NULL THEN
vSQL := vSQL||' AND loc.COMB_ISTAT_COD = '''||P_ISTAT_CITTA||''' ';
END IF;
IF P_PLAY_PLAYER_COD IS NOT NULL THEN
vSQL := vSQL||' AND LOC.PLAY_PLAYER_COD = '''||P_PLAY_PLAYER_COD||''' ';
END IF;
IF P_LOC_DATA IS NOT NULL THEN
vSQL := vSQL||' AND TO_TIMESTAMP ('''||P_LOC_DATA||''' , ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN ';
END IF;
Well I always find code that uses bind variables rather than concatenation of values easier to read (and it is much better practice). You don't say how the SQL will be run, but assuming a REF CURSOR you could do it like this:
vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 ';
IF P_LOC_LOCALITA_COD IS NOT NULL THEN
vSQL := vSQL||' AND LOC.LOC_LOCALITA_COD = :P_LOC_LOCALITA_COD ';
ELSE
vSQL := vSQL||' AND (1=1 OR :P_LOC_LOCALITA_COD IS NULL)';
END IF;
IF P_ISTAT_CITTA IS NOT NULL THEN
vSQL := vSQL||' AND loc.COMB_ISTAT_COD = :P_ISTAT_CITTA ';
ELSE
vSQL := vSQL||' AND (1=1 OR :P_ISTAT_CITTA IS NULL)';
END IF;
IF P_PLAY_PLAYER_COD IS NOT NULL THEN
vSQL := vSQL||' AND LOC.PLAY_PLAYER_COD = :P_PLAY_PLAYER_COD ';
ELSE
vSQL := vSQL||' AND (1=1 OR :P_PLAY_PLAYER_COD IS NULL)';
END IF;
IF P_LOC_DATA IS NOT NULL THEN
vSQL := vSQL||' AND TO_TIMESTAMP (:P_LOC_DATA, ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN ';
ELSE
vSQL := vSQL||' AND (1=1 OR :P_LOC_DATA IS NULL)';
END IF;
OPEN refcur FOR vSQL USING P_LOC_LOCALITA_COD, P_ISTAT_CITTA, P_PLAY_PLAYER_COD, P_LOC_DATA;
I added the ELSE clauses because for native dynamic SQL the number of bind variables in the statement has to be fixed. If using the DBMS_SQL package you don't need to do that.
As for avoiding the IFs, you could do this:
vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 ';
|| CASE WHEN P_LOC_LOCALITA_COD IS NOT NULL THEN
' AND LOC.LOC_LOCALITA_COD = :P_LOC_LOCALITA_COD '
ELSE
' AND (1=1 OR :P_LOC_LOCALITA_COD IS NULL)'
END
|| CASE WHEN P_ISTAT_CITTA IS NOT NULL THEN
' AND loc.COMB_ISTAT_COD = :P_ISTAT_CITTA '
ELSE
' AND (1=1 OR :P_ISTAT_CITTA IS NULL)'
END
... etc.
Obviously you now have CASEs instead, but at least you lose all the vSQL := vSQL || bits.
If you are adding a lot of similar conditions you could wrap the logic in a function like:
vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 ';
|| and_condition ('LOC.LOC_LOCALITA_COD', 'BV1', P_LOC_LOCALITA_COD)
|| and_condition ('loc.COMB_ISTAT_COD', 'BV2', P_ISTAT_CITTA)
... etc.
(That doesn't work for the BETWEEN condition of course).
"More readable" is a little subjective but a couple of options if you don't like the IF THEN blocks are:
vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 ';
vSQL := vSQL||
NVL2(P_LOC_LOCALITA_COD,
' AND LOC.LOC_LOCALITA_COD = '''||P_LOC_LOCALITA_COD||''' ',
NULL);
vSQL := vSQL||
NVL2(P_ISTAT_CITTA,
' AND loc.COMB_ISTAT_COD = '''||P_ISTAT_CITTA||''' ',
NULL);
vSQL := vSQL||
NVL2(P_PLAY_PLAYER_COD,
' AND LOC.PLAY_PLAYER_COD = '''||P_PLAY_PLAYER_COD||''' ',
NULL);
vSQL := vSQL||
NVL2(P_LOC_DATA,
' AND TO_TIMESTAMP ('''||P_LOC_DATA||''' , ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN ',
NULL);
or
vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 '
||NVL2(P_LOC_LOCALITA_COD,
' AND LOC.LOC_LOCALITA_COD = '''||P_LOC_LOCALITA_COD||''' ',
NULL)
||NVL2(P_ISTAT_CITTA,
' AND loc.COMB_ISTAT_COD = '''||P_ISTAT_CITTA||''' ',
NULL)
||NVL2(P_PLAY_PLAYER_COD,
' AND LOC.PLAY_PLAYER_COD = '''||P_PLAY_PLAYER_COD||''' ',
NULL)
||NVL2(P_LOC_DATA,
' AND TO_TIMESTAMP ('''||P_LOC_DATA||''' , ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN ',
NULL);
Hope it helps...
Reading your answer I found this formulation. What do you think about it?
SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN
FROM ENI_SAG_TSF_LOCALITA_DEF loc
WHERE 1 = 1
AND (LOC.LOC_LOCALITA_COD = :P_LOC_LOCALITA_COD OR :P_LOC_LOCALITA_COD IS NULL)
AND (loc.COMB_ISTAT_COD = :P_ISTAT_CITTA OR :P_ISTAT_CITTA IS NULL)
AND (LOC.PLAY_PLAYER_COD = :P_PLAY_PLAYER_COD OR LOC.PLAY_PLAYER_COD IS NULL)
AND (TO_TIMESTAMP (:P_LOC_DATA, 'DD/MM/YYYY HH24:MI:SS.FF3') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN OR :P_LOC_DATA IS NULL)

Killing a task doesn't unlock tables in SQL Developer

I'm using Oracle SQL Developer version 3.0.04 to interface with an 11g database over a VPN to my company server. I've noticed that after killing a task via the Task Progress window, it does not actually "kill" the task outright. I've read in some forums that what is going on is that Oracle is trying to "roll back" the changes made by the procedure I'm calling, but I can't imagine it's taking more than 10 minutes to roll back to my last commit after 5 minutes of run time. This leads me to believe that it is continuing to run anyway.
I can message the DBA to kill my session, which frees up the lock on the tables the process was using (as well as the source code of the package so I can edit it again), but this is not an optimal solution. I do not have command-line access to the DB, and I do not have administrator privileges through SQL Developer. Is there any way to definitively kill the task I started, a la kill -9?
I use this generic thinggy to see whats running in the schema, and use it to monitor
rollback. It uses concepts stolen from various places on the net, including ask tom.
DECLARE
SID INTEGER;
LOCKWAIT VARCHAR2(100);
OSUSER VARCHAR2(32);
PROGRAM VARCHAR2(48);
LOGIN_TIME DATE;
SQL_TEXT VARCHAR2(32760);
estimated_rollback_megs INTEGER;
STATUS VARCHAR2(8);
OSUSERX VARCHAR2(100);
PROGRAMX VARCHAR2(100);
SIDX INTEGER;
STATUSX VARCHAR2(100);
MACHINEX VARCHAR2(100);
LOGON_TIMEX DATE;
LOCKED_OBJECT_NAME VARCHAR2(100);
processcount integer := 0;
CURSOR raw_data IS
WITH
sessionInfo AS
(
SELECT *
FROM V$SESSION
WHERE USERNAME = USER -- Just data for my current schema
ORDER BY SID
)
SELECT si.SID,
si.LOCKWAIT,
si.OSUSER,
si.PROGRAM,
si.LOGON_TIME,
si.STATUS,
(
SELECT ROUND(USED_UBLK*8/1024,1)
FROM V$TRANSACTION,
sessionInfo
WHERE sessionInfo.TADDR = V$TRANSACTION.ADDR
AND sessionInfo.SID = si.SID
) estimated_rollback_megs,
(
SELECT (MAX(DECODE(PIECE, 0,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 1,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 2,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 3,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 4,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 5,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 6,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 7,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 8,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 9,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 10,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 11,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 12,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 13,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 14,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 15,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 16,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 17,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 18,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 19,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 20,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 21,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 22,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 23,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 24,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 25,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 26,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 27,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 28,SQL_TEXT,NULL)) ||
MAX(DECODE(PIECE, 29,SQL_TEXT,NULL)))
FROM V$SQLTEXT_WITH_NEWLINES
WHERE ADDRESS = SI.SQL_ADDRESS AND
PIECE < 30
) SQL_TEXT
FROM sessionInfo si;
CURSOR LONG_OPERATIONS(SIDx number) IS
SELECT VL.MESSAGE,
VL.START_TIME,
VL.LAST_UPDATE_TIME,
VL.TIME_REMAINING
FROM V$SESSION_LONGOPS VL,
V$SESSION V
WHERE VL.USERNAME LIKE USER AND
V.SID = VL.SID AND
V.SERIAL# = VL.SERIAL# AND
V.SID = SIDx AND
VL.TIME_REMAINING > 0
ORDER BY LAST_UPDATE_TIME DESC;
message VARCHAR2(100);
startTime DATE;
lastUpdateTime DATE;
timeRemaining VARCHAR2(100);
PROCEDURE print_sql_statement
(
printThis IN VARCHAR2,
Plen IN NUMBER DEFAULT 132,
Pwhsp IN VARCHAR2 DEFAULT -- newline+space+tab+comma
CHR(10) || CHR(32) || CHR(9) || ','
)
IS
NL CONSTANT VARCHAR2(1) := CHR(10); -- newline character (OS-independent)
SP CONSTANT VARCHAR2(1) := CHR(32); -- space character
TB CONSTANT VARCHAR2(1) := CHR(9); -- tab character
CM CONSTANT VARCHAR2(1) := ','; -- comma
substringStart INTEGER := 1; -- start of string to print
substringEnd INTEGER; -- end of substring to print
endOfString INTEGER := LENGTH(printThis); -- end of string to print
newLinePosition INTEGER; -- point where newline found
stringLength INTEGER := GREATEST(LEAST(Plen, 255), 10); -- 10 <= len <= 255!
BEGIN
NULL;
END print_sql_statement;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.PUT_LINE('Monitor for ' || USER);
OPEN raw_data;
LOOP
FETCH raw_data INTO
SID,
LOCKWAIT,
OSUSER,
PROGRAM,
LOGIN_TIME,
STATUS,
estimated_rollback_megs,
SQL_TEXT;
EXIT WHEN raw_data%NOTFOUND;
processcount := processcount + 1;
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE(OSUSER || ' Owns Session ' || SID || ' STATUS ' || STATUS);
DBMS_OUTPUT.PUT_LINE('Running ' || PROGRAM || ' Since ' || TO_CHAR(LOGIN_TIME,'MM/DD HH24:MI:SS'));
OPEN LONG_OPERATIONS(SID);
LOOP
FETCH LONG_OPERATIONS INTO
message,
startTime,
lastUpdateTime,
timeRemaining;
EXIT WHEN LONG_OPERATIONS%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(' ' || message);
DBMS_OUTPUT.PUT_LINE(' START: ' || TO_CHAR(startTime,'DD HH24:MI:SS') ||
' UPDATE: ' || TO_CHAR(lastUpdateTime, 'DD HH24:MI:SS') ||
' REMAINING: ' || timeRemaining);
DBMS_OUTPUT.PUT_LINE(' ');
END LOOP;
CLOSE LONG_OPERATIONS;
IF estimated_rollback_megs > 0 then
DBMS_OUTPUT.PUT_LINE('Estimated megs of rollback ' || estimated_rollback_megs);
END IF;
IF LOCKWAIT IS NOT NULL THEN
SELECT SID
INTO SIDX
FROM V$LOCK
WHERE ID1 =
(
SELECT ID1
FROM V$LOCK
WHERE KADDR = LOCKWAIT
) AND BLOCK = 1;
DBMS_OUTPUT.PUT_LINE('The session is waiting on a lock held by session ' || SIDX);
select OBJECT_TYPE || ':' || OBJECT_NAME || ':' || SUBOBJECT_NAME THINGY
INTO LOCKED_OBJECT_NAME
from dba_objects
where object_id =
(
select object_id
from v$locked_object
where session_id = SIDX
);
DBMS_OUTPUT.PUT_LINE('The locked object is ' || LOCKED_OBJECT_NAME);
SELECT OSUSER, PROGRAM, SID, STATUS, MACHINE, LOGON_TIME
INTO OSUSERX, PROGRAMX, SIDX, STATUSX, MACHINEX, LOGON_TIMEX
FROM V$SESSION
WHERE SID = SIDX;
DBMS_OUTPUT.PUT_LINE(SIDX || ': ' || OSUSER || ' Using ' || PROGRAMX || ' STATUS ' || STATUSX);
DBMS_OUTPUT.PUT_LINE(SIDX || ': LOGGED IN ON ' || MACHINEX || ' SINCE ' ||
TO_CHAR(LOGON_TIMEX, 'MM/DD HH24:MI:SS'));
END IF;
IF SUBSTR(SQL_TEXT, 1, 16) <> 'WITH SESSIONINFO' THEN
print_sql_statement(SQL_TEXT, 132);
DBMS_OUTPUT.PUT_LINE('');
ELSE
NULL;
END IF;
END LOOP;
CLOSE raw_data;
DBMS_OUTPUT.PUT_LINE(processcount || ' sessions found');
END;

Resources