I've come across some odd behavior related to RPAD ... figured I'm missing something obvious, hoping somebody can help me out.
I'm just trying to format some simple output ... and reduced the test case to very simple case:
set serverout on
declare
lc_wid CONSTANT number := 10;
lc_sep CONSTANT varchar2(10) := ' : ';
lc_NOCOLOR CONSTANT varchar2(100) := chr(27)||'[0m';
lc_RED CONSTANT varchar2(100) := chr(27)||'[32m'||chr(27)||'[1;31m';
lc_GREEN CONSTANT varchar2(100) := chr(27)||'[32m'||chr(27)||'[1;32m';
lc_YELLOW CONSTANT varchar2(100) := chr(27)||'[32m'||chr(27)||'[1;33m';
begin
dbms_output.put_line ( lc_sep || lc_GREEN || 'test' || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || 'test' || lc_sep );
dbms_output.put_line ( lc_sep || lc_GREEN || rpad('test' ,lc_wid,' ') || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || rpad('test' ,lc_wid,' ') || lc_sep );
dbms_output.put_line ( lc_sep || lc_GREEN || rpad('testing' ,lc_wid,' ') || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || rpad('testing' ,lc_wid,' ') || lc_sep );
dbms_output.put_line ( lc_sep || lc_GREEN || rpad('something',lc_wid,' ') || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || rpad('something',lc_wid,' ') || lc_sep );
end;
/
(Yep, I'm mucking with colors! fun ... )
That spits out the following:
as you can see, the short text with no RPAD aligns fine ... and the longer text with rpad aligns fine, however, the "test" and "testing" text are doing something "different" ... O.o
now if I change rpad to pad with "." . it works fine .
set serverout on
declare
lc_wid CONSTANT number := 10;
lc_sep CONSTANT varchar2(10) := ' : ';
lc_NOCOLOR CONSTANT varchar2(100) := chr(27)||'[0m';
lc_RED CONSTANT varchar2(100) := chr(27)||'[32m'||chr(27)||'[1;31m';
lc_GREEN CONSTANT varchar2(100) := chr(27)||'[32m'||chr(27)||'[1;32m';
lc_YELLOW CONSTANT varchar2(100) := chr(27)||'[32m'||chr(27)||'[1;33m';
begin
dbms_output.put_line ( lc_sep || lc_GREEN || 'test' || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || 'test' || lc_sep );
dbms_output.put_line ( lc_sep || lc_GREEN || rpad('test' ,lc_wid,'.') || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || rpad('test' ,lc_wid,'.') || lc_sep );
dbms_output.put_line ( lc_sep || lc_GREEN || rpad('testing' ,lc_wid,'.') || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || rpad('testing' ,lc_wid,'.') || lc_sep );
dbms_output.put_line ( lc_sep || lc_GREEN || rpad('something',lc_wid,'.') || lc_NOCOLOR || lc_sep );
dbms_output.put_line ( lc_sep || rpad('something',lc_wid,'.') || lc_sep );
end;
/
so ... it seems short text doesn't work properly with those color codes AND RPAD ... but I'm wondering why ?
Trying to understand what's going on here.
[edit]
sorry, for what it's worth, I'm running in Oracle 12.1.0.2.0
[/edit]
Related
The below code is used to create the stored procedure and this is how the stored procedure is called. Stored procedure is throwing ORA-20000: ORA-00913: too many values
BEGIN EDW_ODS_DELETE_RECORDS_PKG.MAIN('EDWFIN', 'PSP_LABOR_ADJUSTMENTS_F'); END;
create or replace
PACKAGE BODY "EDW_ODS_DELETE_RECORDS_PKG" AS
CON_EDW_IUD_FLAG CONSTANT CHAR := 'D';
CON_CURRENT_FLAG CONSTANT CHAR := 'N';
CON_DELETED_FLAG CONSTANT CHAR := 'Y';
PROCEDURE main (table_schema_in IN VARCHAR2, target_table_alias_in IN VARCHAR2) AS
v_source_schema VARCHAR2(30);
v_source_table_name VARCHAR2(30);
v_target_schema VARCHAR2(30);
v_target_table_name VARCHAR2(30);
v_source_table_key VARCHAR2(1000);
v_target_table_key VARCHAR2(1000);
v_table_type VARCHAR2(20);
v_last_deleted_date DATE;
v_delete_control_id NUMBER := 0;
v_target_table_alias VARCHAR2(30);
v_arc_target_table_name VARCHAR2(30);
BEGIN
SELECT SOURCE_TABLE_SCHEMA, SOURCE_TABLE_NAME, SOURCE_TABLE_KEY,
TARGET_TABLE_SCHEMA, TARGET_TABLE_NAME, TARGET_TABLE_KEY,
TABLE_TYPE, LAST_DELETED_DATE, DELETE_CONTROL_ID,
TARGET_TABLE_ALIAS,
ARC_TARGET_TABLE_NAME
INTO
v_source_schema, v_source_table_name, v_source_table_key,
v_target_schema, v_target_table_name, v_target_table_key,
v_table_type, v_last_deleted_date, v_delete_control_id,
v_target_table_alias,
v_arc_target_table_name
FROM EDW_ODS_DWH_DELETES_CONTROL
WHERE target_table_schema = table_schema_in AND target_table_alias = target_table_alias_in;
DBMS_OUTPUT.PUT_LINE ('Values : ' || v_last_deleted_date);
v_source_table_key := REPLACE(v_source_table_key, '~', ' || ''~'' || ');
v_target_table_key := REPLACE(v_target_table_key, '~', ' || ''~'' || ');
IF v_table_type = 'FACT' THEN
UPDATE_FACT_TABLES (v_source_schema, v_source_table_name, v_source_table_key,
v_target_schema, v_target_table_name, v_target_table_key,
v_last_deleted_date, v_delete_control_id,v_arc_target_table_name);
ELSE
UPDATE_DIMENSION_TABLES (v_source_schema, v_source_table_name, v_source_table_key,
v_target_schema, v_target_table_name, v_target_table_key,
v_last_deleted_date, v_delete_control_id, v_table_type);
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
ERROR_LOG(v_delete_control_id, table_schema_in, target_table_alias_in,
SQLERRM, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
RAISE;
END main;
PROCEDURE UPDATE_FACT_TABLES (source_schema_in IN VARCHAR2, source_table_name_in IN VARCHAR2, source_table_key_in IN VARCHAR2,
target_schema_in IN VARCHAR2, target_table_name_in IN VARCHAR2, target_table_key_in IN VARCHAR2,
last_deleted_date_in IN DATE, delete_control_id_in IN NUMBER, arc_target_table_name IN VARCHAR2) AS
v_source_stage_table VARCHAR2(70);
v_target_fact_table VARCHAR2(70);
v_target_arc_table VARCHAR2(70);
query_fetch_deleted_recs CLOB;
query_insert_into_arc CLOB;
query_delete_from_fact CLOB;
v_delete_count NUMBER;
v_insert_count NUMBER;
v_last_deleted_date VARCHAR2(100) := TO_CHAR(last_deleted_date_in,'MM/DD/YYYY HH24:MI:SS');
BEGIN
v_source_stage_table := source_schema_in || '.' || source_table_name_in;
v_target_fact_table := target_schema_in || '.' || target_table_name_in;
v_target_arc_table := target_schema_in || '.' || arc_target_table_name;
query_fetch_deleted_recs := ' SELECT * FROM ' || v_source_stage_table ||
' STAGING_TABLE WHERE STAGING_TABLE.' || source_table_key_in || ' = FACT_TABLE.' || target_table_key_in ||
' AND NVL(STAGING_TABLE.EDW_IUD_FLAG, ''X'') = '''|| CON_EDW_IUD_FLAG ||
''' AND STAGING_TABLE.EDW_UPDATE_DATE_TIME >= TO_DATE('''|| v_last_deleted_date || ''', ''MM/DD/YYYY HH24:MI:SS'')';
DBMS_OUTPUT.PUT_LINE ('Query : ' || query_fetch_deleted_recs);
query_insert_into_arc := 'INSERT INTO ' || v_target_arc_table || ' SELECT * FROM ' || v_target_fact_table ||
' FACT_TABLE WHERE EXISTS (' || query_fetch_deleted_recs || ')';
query_delete_from_fact := 'DELETE FROM ' || v_target_fact_table ||
' FACT_TABLE WHERE EXISTS (' || query_fetch_deleted_recs || ')';
DBMS_OUTPUT.PUT_LINE ('Insert Query : ' || query_insert_into_arc);
EXECUTE IMMEDIATE query_insert_into_arc;
v_insert_count := SQL%ROWCOUNT;
EXECUTE IMMEDIATE query_delete_from_fact;
v_delete_count := SQL%ROWCOUNT;
COMMIT;
DBMS_OUTPUT.PUT_LINE ('Results : ' || v_insert_count ||v_delete_count);
--IF v_insert_count > 0 AND v_delete_count > 0 THEN
UPDATE_LAST_DELETED_DATE(v_source_stage_table, delete_control_id_in);
--END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END UPDATE_FACT_TABLES;
PROCEDURE UPDATE_DIMENSION_TABLES (source_schema_in IN VARCHAR2, source_table_name_in IN VARCHAR2, source_table_key_in IN VARCHAR2,
target_schema_in IN VARCHAR2, target_table_name_in IN VARCHAR2, target_table_key_in IN VARCHAR2,
last_deleted_date_in IN DATE, delete_control_id_in IN NUMBER, table_type_in IN VARCHAR2) AS
v_source_stage_table VARCHAR2(70);
v_target_dim_table VARCHAR2(70);
query_fetch_deleted_recs CLOB;
query_update_dim1 CLOB;
query_update_dim2 CLOB;
query_update_dim6 CLOB;
v_update_count NUMBER;
v_last_deleted_date VARCHAR2(100) := TO_CHAR(last_deleted_date_in,'MM/DD/YYYY HH24:MI:SS');
BEGIN
v_source_stage_table := source_schema_in || '.' || source_table_name_in;
v_target_dim_table := target_schema_in || '.' || target_table_name_in;
query_fetch_deleted_recs := ' SELECT * FROM ' || v_source_stage_table ||
' STAGING_TABLE WHERE STAGING_TABLE.' || source_table_key_in || ' = DIM_TABLE.' || target_table_key_in ||
' AND NVL(STAGING_TABLE.EDW_IUD_FLAG, ''X'') = '''|| CON_EDW_IUD_FLAG ||
''' AND STAGING_TABLE.EDW_UPDATE_DATE_TIME >= TO_DATE('''|| v_last_deleted_date || ''', ''MM/DD/YYYY HH24:MI:SS'')';
IF table_type_in = 'DIMTYP1' THEN
query_update_dim1 := 'UPDATE ' || v_target_dim_table || ' DIM_TABLE' ||
' SET DIM_TABLE.DELETE_FLAG = ''' || CON_DELETED_FLAG || ''', DIM_TABLE.EDW_UPDATE_DATE_TIME = SYSDATE, DIM_TABLE.EDW_UPDATED_BY = ''ETL'''||
' WHERE (DIM_TABLE.DELETE_FLAG = ''N'' OR DIM_TABLE.DELETE_FLAG IS NULL)' ||
' AND EXISTS (' || query_fetch_deleted_recs || ')';
DBMS_OUTPUT.PUT_LINE ('Query : ' || query_update_dim1);
EXECUTE IMMEDIATE query_update_dim1;
v_update_count := SQL%ROWCOUNT;
ELSIF table_type_in = 'DIMTYP2' THEN
query_update_dim2 := 'UPDATE ' || v_target_dim_table || ' DIM_TABLE' ||
' SET DIM_TABLE.CURRENT_FLAG = ''' || CON_CURRENT_FLAG || ''', DIM_TABLE.EDW_END_DATE = TRUNC(SYSDATE), ' ||
' EDW_UPDATE_DATE_TIME = SYSDATE, EDW_UPDATED_BY = ''ETL'''||
' WHERE DIM_TABLE.CURRENT_FLAG = ''Y'' AND EXISTS (' || query_fetch_deleted_recs || ')';
EXECUTE IMMEDIATE query_update_dim2;
v_update_count := SQL%ROWCOUNT;
ELSIF table_type_in = 'DIMTYP6' THEN
query_update_dim6 := 'UPDATE ' || v_target_dim_table || ' DIM_TABLE' ||
' SET DIM_TABLE.EDW_END_DATE = TRUNC(SYSDATE) , ' ||
' DIM_TABLE.DELETE_FLAG = ''' || CON_DELETED_FLAG || ''', DIM_TABLE.EDW_UPDATE_DATE_TIME = SYSDATE, DIM_TABLE.EDW_UPDATED_BY = ''ETL'''||
' WHERE DIM_TABLE.EDW_END_DATE = TO_DATE(''12/31/2099'',''MM/DD/YYYY'') AND EXISTS (' || query_fetch_deleted_recs || ')';
EXECUTE IMMEDIATE query_update_dim6;
v_update_count := SQL%ROWCOUNT;
END IF;
COMMIT;
DBMS_OUTPUT.PUT_LINE ('Results : ' || v_update_count);
--IF v_update_count > 0 THEN
UPDATE_LAST_DELETED_DATE(v_source_stage_table, delete_control_id_in);
--END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END UPDATE_DIMENSION_TABLES;
PROCEDURE UPDATE_LAST_DELETED_DATE (source_stage_table_in IN VARCHAR2, delete_control_id_in IN NUMBER) AS
query_max_updated_query CLOB;
v_max_updated_date DATE;
BEGIN
query_max_updated_query := 'SELECT MAX(STAGE_TABLE.EDW_UPDATE_DATE_TIME) FROM ' || source_stage_table_in || ' STAGE_TABLE ';
EXECUTE IMMEDIATE query_max_updated_query INTO v_max_updated_date;
UPDATE EDW_ODS_DWH_DELETES_CONTROL
SET EDW_UPDATE_DATE_TIME = SYSDATE, EDW_UPDATED_BY = 'ETL', LAST_DELETED_DATE = v_max_updated_date
WHERE DELETE_CONTROL_ID = delete_control_id_in;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END UPDATE_LAST_DELETED_DATE;
PROCEDURE ERROR_LOG (delete_record_key_in IN NUMBER, table_schema_in IN VARCHAR2, target_table_in IN VARCHAR2,
error_message_in IN VARCHAR2, error_backtrace_in IN VARCHAR2 := NULL) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO edw_ods_dwh_deletes_log VALUES (delete_record_key_in, target_table_in, table_schema_in, SYSDATE, 'ETL',
error_message_in, error_backtrace_in);
COMMIT;
RAISE_APPLICATION_ERROR(-20000, error_message_in);
EXCEPTION
WHEN OTHERS THEN
RAISE;
END ERROR_LOG;
END EDW_ODS_DELETE_RECORDS_PKG;
Your error is, as the ORA-00913 error message states, that in one of your statements you are passing too many values.
Cause:
As an example, if you have the table:
CREATE TABLE table_name (a NUMBER, b NUMBER);
And you do either of:
INSERT INTO table_name VALUES (1,2,3);
INSERT INTO table_name (a,b) VALUES (1,2,3);
Then you get the error:
ORA-00913: too many values
As you are trying to insert three values into two columns.
If you name all the columns:
INSERT INTO table_name (a,b,c) VALUES (1,2,3);
Then you will get a more expressive error message:
ORA-00904: "C": invalid identifier
Solution:
Go through every statement and explicitly name the columns you are inserting and make sure you are selecting the same number of columns.
For example, in the UPDATE_FACT_TABLES procedure you have:
query_insert_into_arc := 'INSERT INTO ' || v_target_arc_table || ' SELECT * FROM ' || v_target_fact_table ||
' FACT_TABLE WHERE EXISTS (' || query_fetch_deleted_recs || ')';
It would be better to be:
query_insert_into_arc := 'INSERT INTO ' || v_target_arc_table || ' (col1, col2, col3, col4)
|| ' SELECT other_col1, other_col2, other_col3, other_col3'
|| ' FROM ' || v_target_fact_table || ' FACT_TABLE'
|| ' WHERE EXISTS (' || query_fetch_deleted_recs || ')';
Then you know which columns are being inserted where and you will get a more detailed error message if you are trying to insert into a column that does not exist.
You also do not need to use:
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
As the default behaviour is to rollback the transaction when an exception is raised.
Additionally, you should not raise an exception in your autonomous transaction as you are already raising the exception in the non-autonomous procedure.
PROCEDURE ERROR_LOG (
delete_record_key_in IN NUMBER,
table_schema_in IN VARCHAR2,
target_table_in IN VARCHAR2,
error_message_in IN VARCHAR2,
error_backtrace_in IN VARCHAR2 := NULL
)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO edw_ods_dwh_deletes_log (
delete_record_key, -- Give the columns their proper names
target_table,
table_schema,
change_date,
col1,
error_message,
error_backtrace
) VALUES (
delete_record_key_in,
target_table_in,
table_schema_in,
SYSDATE,
'ETL',
error_message_in,
error_backtrace_in
);
COMMIT;
-- Remove raising the exception.
END ERROR_LOG;
I have a source database and I should insert or update some rows in another DB based on my source DB.
My Problem is when updating or inserting raw datatypes, just half of row value comes in target DB.
my raw part of code is:
v_raw RAW(16);
FOR i IN 1 .. v_col_cnt
LOOP
CASE v_desc_tab ( i ).col_type
WHEN 1
THEN
DBMS_SQL.define_column ( v_cursor_id, i, v_namevar, v_desc_tab ( i ).col_max_len );
WHEN 2
THEN
DBMS_SQL.define_column ( v_cursor_id, i, v_numvar );
WHEN 12
THEN
DBMS_SQL.define_column ( v_cursor_id, i, v_datevar );
WHEN 96
THEN
DBMS_SQL.define_column ( v_cursor_id, i, v_charvar, v_desc_tab ( i ).col_max_len );
WHEN 112
THEN
DBMS_SQL.define_column ( v_cursor_id, i, v_clob );
WHEN 23
THEN
DBMS_SQL.define_column ( v_cursor_id, i, v_raw, v_desc_tab ( i ).col_max_len );
ELSE
DBMS_OUTPUT.PUT_LINE('another type');
END CASE;
END LOOP;
WHILE DBMS_SQL.fetch_rows ( v_cursor_id ) > 0
LOOP
v_insert_str := 'INSERT INTO ' || v_table_name || ' VALUES(' ;
v_update_str := 'UPDATE ' || v_table_name || ' SET ';
v_update_where_str := ' WHERE ';
FOR i IN 1 .. v_col_cnt
LOOP
CASE v_desc_tab ( i ).col_type
WHEN 23
THEN
DBMS_SQL.COLUMN_VALUE ( v_cursor_id, i, v_raw );
v_insert_str := v_insert_str || '''' || v_raw || '''' || ', ';
IF is_index(v_table_name, v_desc_tab ( i ).col_name) != 1
THEN
v_update_str := v_update_str || v_desc_tab ( i ).col_name || ' = ''' || v_raw || '''' || ', ';
ELSE
v_update_where_str := v_update_where_str || v_desc_tab ( i ).col_name || ' = ''' || v_raw || '''' || ' and ';
END IF;
END CASE;
END LOOP;
and after creating insert or update command, it will be updated or inserted.
for example a value in my source DB is: 0022F12C24984AECA5E529C533B067B3
but in Target it comes like : 0022F12C24984AEC
I tried RAW(32) and RAW(64) but it didn't work.
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
The goal is to write a method that will allow me to easily log input parameter values. I know I can do this manually, but I am trying to figure out if I can do this dynamically. So far by looking on the internet it seems like the answer is no.
I am currently working with Oracle 12.1.0.2.0.
Sample code:
CREATE OR REPLACE PROCEDURE pr_t1( i_a VARCHAR2, i_b VARCHAR2 )
AS
v_sql_1 VARCHAR2( 2000 );
v_sql_2 VARCHAR2( 2000 );
v_output_1 VARCHAR2( 2000 );
v_output_2 VARCHAR2( 2000 );
v_args VARCHAR2( 2000 );
BEGIN
SELECT ''''''''' || '
|| LISTAGG( '''[' || a.argument_name || '='' || ' || a.argument_name || ' || '']''', ' || '', '' || ' )
WITHIN GROUP (ORDER BY a.sequence)
|| '|| '''''''''
AS args
INTO v_args
FROM user_arguments a
WHERE a.object_name = 'PR_T1'
AND in_out LIKE '%IN%'
AND a.sequence = 1;
v_sql_1 := 'BEGIN SELECT ' || '''[i_a=' || i_a || ']''' || ' INTO :p1 FROM DUAL; END;'; -- works
DBMS_OUTPUT.put_line( 'v_sql_1: ' || v_sql_1 );
EXECUTE IMMEDIATE v_sql_1 USING OUT v_output_1;
DBMS_OUTPUT.put_line( 'v_output: ' || v_output_1 );
DBMS_OUTPUT.put_line( '----------------------------------------------------' );
DBMS_OUTPUT.put_line( 'v_args: ' || v_args );
v_sql_2 := 'BEGIN SELECT ' || v_args || ' INTO :p1 FROM DUAL; END;';
DBMS_OUTPUT.put_line( 'v_sql_2: ' || v_sql_2 );
--EXECUTE IMMEDIATE v_sql_2 USING OUT v_output_2; -- How to make this work?
DBMS_OUTPUT.put_line( 'v_output_2: ' || v_output_2 );
END pr_t1;
-------------------------------
-- Call the procedure
SET SERVEROUTPUT ON;
EXEC pr_t1('1', '2');
Sample Result:
v_sql_1: BEGIN SELECT '[i_a=1]' INTO :p1 FROM DUAL; END;
v_output: [i_a=1]
----------------------------------------------------
v_args: '''' || '[I_A=' || I_A || ']'|| ''''
v_sql_2: BEGIN SELECT '''' || '[I_A=' || I_A || ']'|| '''' INTO :p1 FROM DUAL; END;
v_output_2:
I am trying to figure out what can I do such that I can dynamically make "v_sql_2" to have the value of "1".
Any help will be appreciated.
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