I have the following procedure, but no scheduler job is getting created and I cannot find any errors while running the job. How can I debug this and what is wrong with the code?
CREATE OR REPLACE PROCEDURE test
IS
prod_no varchar2(32);
prod_date date;
employee varchar2(32);
assurer varchar2(32);
prod_description varchar2(32);
prod_days number;
assig varchar2(32);
reg_no number;
l_v number;
BEGIN
prod_no := '300';
prod_date := sysdate;
employee := 'SAM';
assurer := 'MAT';
prod_description := 'test';
prod_days := 1;
assig := 'A';
reg_no := 1;
DBMS_SCHEDULER.create_job (
job_name => DBMS_SCHEDULER.generate_job_name ('FR'),
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN test_job('
|| i_prod_no
|| ','''
|| prod_date
|| ','''
|| employee
|| ','''
|| assurer
|| ','''
|| prod_description
|| ','''
|| prod_days
|| ','''
|| assig
|| ','''
|| reg_no
|| '''); end;',
start_date => SYSDATE,
end_date => NULL,
enabled => TRUE,
comments => 'test product'
);
commit;
exception
when others then
dbms_output.put_line (dbms_utility.format_error_stack);
END test;
/
If job action is syntactically incorrect you won't get any warning, but you won't get a job either.
Here is your statement:
BEGIN test_job(300,'04-OCT-12,'SAM,'MAT,'test,'1,'A,'1'); end;
You are missing some ' to close the string values.
CREATE OR REPLACE PROCEDURE test
IS
prod_no varchar2(32);
prod_date date;
employee varchar2(32);
assurer varchar2(32);
prod_description varchar2(32);
prod_days number;
assig varchar2(32);
reg_no number;
l_v number;
l_statement varchar2(32767);
BEGIN
prod_no := '300';
prod_date := sysdate;
employee := 'SAM';
assurer := 'MAT';
prod_description := 'test';
prod_days := 1;
assig := 'A';
reg_no := 1;
l_statement := 'BEGIN test_job('
|| i_prod_no
|| ','''
|| prod_date
|| ','''
|| employee
|| ','''
|| assurer
|| ','''
|| prod_description
|| ','''
|| prod_days
|| ','''
|| assig
|| ','''
|| reg_no
|| '''); end;'
dbms_output.put_line(l_statement);
DBMS_SCHEDULER.create_job (
job_name => DBMS_SCHEDULER.generate_job_name ('FR'),
job_type => 'PLSQL_BLOCK',
job_action => l_statement,
start_date => SYSDATE,
end_date => NULL,
enabled => TRUE,
comments => 'test product'
);
commit;
exception
when others then
dbms_output.put_line (dbms_utility.format_error_stack);
END test;
/
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've been trying to identify what's wrong with the Insert Statement in the Execute Immediate for few hours without luck. Made sure that I am not missing any commas or entering any incorrect character.
I have gone through all the answers on SO and other websites trying to figure out what could I be doing wrong but no luck.
Running this function results in the following error (error line starts with "-->" Please ignore it as its just for highlighting purpose):
ORA-00936: missing expression
ORA-06512: at "BDW_AMPS.COUNT_RECORDS", line 62
and here's the PL/SQL Code for the function:
CREATE OR REPLACE FUNCTION count_records (
p_test_case_id IN NUMBER,
p_table_name IN VARCHAR2
) RETURN VARCHAR2 IS
v_amt_recs INT;
v_test_result VARCHAR2(10);
v_threshold_val VARCHAR2(10);
v_test_suite_table VARCHAR2(100);
v_test_result_id NUMBER;
v_batch_id NUMBER;
v_report_id NUMBER;
v_test_seq_no NUMBER;
v_session_name VARCHAR2(100);
v_error_description VARCHAR2(100);
v_process_by VARCHAR2(100);
BEGIN
v_test_suite_table := 'bdw_amps.spares_bdw_test_suite';
v_process_by := 'INFORMATICA';
EXECUTE IMMEDIATE 'SELECT THRESHHOLD_VALUE FROM '
|| v_test_suite_table
|| ' WHERE TEST_CASE_ID = '
|| p_test_case_id
INTO v_threshold_val;
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || p_table_name
INTO v_amt_recs;
EXECUTE IMMEDIATE 'SELECT BDW_AMPS.SPARES_TEST_SEQ_ID_SEQ.NEXTVAL FROM DUAL'
INTO v_test_result_id;
EXECUTE IMMEDIATE 'SELECT MAX(BATCH_ID) FROM BDW_AMPS.spares_bdw_session_audit
WHERE SESSION_NAME=(SELECT SESSION_NAME FROM '
|| v_test_suite_table
|| ' WHERE TEST_CASE_ID = '
|| p_test_case_id
|| ')'
INTO v_batch_id;
EXECUTE IMMEDIATE 'SELECT REPORT_ID FROM '
|| v_test_suite_table
|| ' WHERE TEST_CASE_ID = '
|| p_test_case_id
INTO v_report_id;
EXECUTE IMMEDIATE 'SELECT TEST_SEQ FROM '
|| v_test_suite_table
|| ' WHERE TEST_CASE_ID = '
|| p_test_case_id
INTO v_test_seq_no;
EXECUTE IMMEDIATE 'SELECT SESSION_NAME FROM '
|| v_test_suite_table
|| ' WHERE TEST_CASE_ID = '
|| p_test_case_id
INTO v_session_name;
IF
v_amt_recs > v_threshold_val
THEN
v_test_result := 'PASS';
--> EXECUTE IMMEDIATE 'INSERT INTO BDW_AMPS.spares_bdw_test_results(
TEST_RESULT_ID,
BATCH_ID,
REPORT_ID,
TEST_CASE_ID,
TEST_SEQ_NO,
TABLE_NAME,
SESSION_NAME,
TEST_RESULT,
PROCESS_DATE,
PROCESS_BY
)
VALUES
('|| v_test_result_id || ',
' || v_batch_id || ',
' || v_report_id || ',
' || p_test_case_id || ',
' || v_test_seq_no || ',
' || p_table_name || ',
' || v_session_name || ',
' || v_test_result || ',
SYSDATE,
' || v_process_by || '
)';
EXECUTE IMMEDIATE 'commit';
ELSE
v_test_result := 'FAIL';
v_error_description := 'Count: ' || v_amt_recs || ' is greater than threshold value: ' || v_threshold_val;
EXECUTE IMMEDIATE 'INSERT INTO BDW_AMPS.spares_bdw_test_results(
TEST_RESULT_ID,
BATCH_ID,
REPORT_ID,
TEST_CASE_ID,
TEST_SEQ_NO,
TABLE_NAME,
SESSION_NAME,
TEST_RESULT,
ERROR_DESCRIPTION,
PROCESS_DATE,
PROCESS_BY
)
VALUES (
'|| v_test_result_id || ',
' || v_batch_id || ',
' || v_report_id || ',
' || p_test_case_id || ',
' || v_test_seq_no || ',
' || p_table_name || ',
' || v_session_name || ',
' || v_test_result || ',
' || v_error_description || ',
SYSDATE,
' || v_process_by || '
)';
EXECUTE IMMEDIATE 'commit';
END IF;
RETURN v_test_result;
END;
Assuming that this is a simplified example of something that really does need to be dynamic, one issue is that the string values are not quoted. (If you'd had date values they would need special handling too.)
For example:
create table demo (numcol number, stringcol varchar2(20));
declare
l_num number := 123;
l_string varchar2(20) := 'Kittens';
l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '||l_string||')';
begin
dbms_output.put_line(l_sql);
execute immediate l_sql;
end;
/
Generated code:
insert into demo(numcol, stringcol) values (123, Kittens)
Fails with:
ORA-00984: column not allowed here
The error will vary depending on the contents of the string. For example, if it contains spaces:
declare
l_num number := 123;
l_string varchar2(20) := 'Kittens are cute';
l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '||l_string||')';
begin
dbms_output.put_line(l_sql);
execute immediate l_sql;
end;
/
Generated code:
insert into demo(numcol, stringcol) values (123, Kittens are cute)
ORA-00917: missing comma
or commas:
declare
l_num number := 123;
l_string varchar2(20) := 'Kittens, Puppies';
l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '||l_string||')';
begin
dbms_output.put_line(l_sql);
execute immediate l_sql;
end;
/
insert into demo(numcol, stringcol) values (123, Kittens, Puppies)
ORA-00913: too many values
You need to build the quoting:
declare
l_num number := 123;
l_string varchar2(20) := 'Kittens, Puppies';
l_sql long := 'insert into demo(numcol, stringcol) values ('||l_num||', '''||l_string||''')';
begin
dbms_output.put_line(l_sql);
execute immediate l_sql;
end;
/
so that you generate
insert into demo(numcol, stringcol) values (123, 'Kittens, Puppies')
(If the string could contain quote characters, that would need more work.)
It's worth always building the dynamic SQL as a variable and printing or logging it on failure, as it's usually pretty clear what the issue is when you can see the code.
Another point is that concatenating values like this is resource-intensive, as Oracle tries to cache SQL statements for reuse, so they will be individually parsed and optimised and take space in the cache, but they will never be reused. If this is going to be frequently run with different values, you should consider using bind variables via the using clause of execute immediate.
Your DML(INSERT) statements do not need EXECUTE IMMEDIATE statements. So, remove them after line 61 :
CREATE OR REPLACE FUNCTION count_records (
p_test_case_id IN NUMBER,
p_table_name IN VARCHAR2
) RETURN VARCHAR2 IS
v_amt_recs INT;
v_test_result VARCHAR2(10);
v_threshold_val VARCHAR2(10);
v_test_suite_table VARCHAR2(100);
v_test_result_id NUMBER;
v_batch_id NUMBER;
v_report_id NUMBER;
v_test_seq_no NUMBER;
v_session_name VARCHAR2(100);
v_error_description VARCHAR2(100);
v_process_by VARCHAR2(100);
BEGIN
v_test_suite_table := 'bdw_amps.spares_bdw_test_suite';
v_process_by := 'INFORMATICA';
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || p_table_name
INTO v_amt_recs;
v_test_result_id := BDW_AMPS.SPARES_TEST_SEQ_ID_SEQ.NEXTVAL;
EXECUTE IMMEDIATE 'SELECT MAX(BATCH_ID) FROM BDW_AMPS.spares_bdw_session_audit
WHERE SESSION_NAME=(SELECT SESSION_NAME FROM '
|| v_test_suite_table
|| ' WHERE TEST_CASE_ID = '
|| p_test_case_id
|| ')'
INTO v_batch_id;
EXECUTE IMMEDIATE 'SELECT THRESHHOLD_VALUE, REPORT_ID, TEST_SEQ,SESSION_NAME FROM '
|| v_test_suite_table
|| ' WHERE TEST_CASE_ID = :caseId'
INTO v_threshold_val,v_report_id,v_test_seq_no,v_session_name
USING p_test_case_id;
IF
v_amt_recs > v_threshold_val
THEN
v_test_result := 'PASS';
INSERT INTO BDW_AMPS.spares_bdw_test_results(
TEST_RESULT_ID,
BATCH_ID,
REPORT_ID,
TEST_CASE_ID,
TEST_SEQ_NO,
TABLE_NAME,
SESSION_NAME,
TEST_RESULT,
PROCESS_DATE,
PROCESS_BY
)
VALUES
( v_test_result_id ,
v_batch_id ,
v_report_id ,
p_test_case_id ,
v_test_seq_no ,
p_table_name ,
v_session_name ,
v_test_result ,
SYSDATE,
v_process_by
);
commit;
ELSE
v_test_result := 'FAIL';
v_error_description := 'Count: ' || v_amt_recs || ' is greater than threshold value: ' || v_threshold_val;
INSERT INTO BDW_AMPS.spares_bdw_test_results(
TEST_RESULT_ID,
BATCH_ID,
REPORT_ID,
TEST_CASE_ID,
TEST_SEQ_NO,
TABLE_NAME,
SESSION_NAME,
TEST_RESULT,
ERROR_DESCRIPTION,
PROCESS_DATE,
PROCESS_BY
)
VALUES (
v_test_result_id ,
v_batch_id ,
v_report_id ,
p_test_case_id ,
v_test_seq_no ,
p_table_name ,
v_session_name ,
v_test_result ,
v_error_description ,
SYSDATE,
v_process_by
);
commit;
END IF;
RETURN v_test_result;
END;
while usage of them are right for SELECT statements because of dynamic table names.
I have to following oracle function, build_select, which create a select request. The return value is in the following format:
select col1 ||'|'||col2 ||'|'||col3 from table;
Below is the build_select function:
create or replace FUNCTION build_select (
p_table_name IN VARCHAR2
)
RETURN VARCHAR2
AS
l_ret VARCHAR2 (32767);
BEGIN
FOR eachcol IN ( SELECT column_name, data_type
, LEAD (column_name), LEAD (data_type)
OVER (
PARTITION BY table_name ORDER BY column_id
)
next_column
FROM all_tab_cols
WHERE table_name = p_table_name
ORDER BY column_id)
LOOP
IF eachcol.data_type = 'CLOB' THEN
l_ret := l_ret || dbms_lob.substr( eachcol.column_name, 3000, 1 ) || CASE WHEN eachcol.next_column IS NULL THEN NULL ELSE ' ||''|''||' END;
ELSE
l_ret := l_ret || eachcol.column_name || CASE WHEN eachcol.next_column IS NULL THEN NULL ELSE ' ||''|''||' END;
END IF;
END LOOP;
IF l_ret IS NULL
THEN
raise_application_error (-20001, 'table ' || p_table_name || ' not found');
END IF;
l_ret := 'select ' || l_ret || ' from ' || p_table_name || ';';
RETURN l_ret;
END build_select;
What I want to do is to test if the data type of the column is CLOB and if so then return it as
dbms_lob.substr( eachcol.column_name, 3000, 1 )
I have added the if else condition in the loop part. But I am getting the error :
PLS 00302 : component DATA_TYPE must de declared.
Any help pls?
I need to do so cause when I am doing a spool of the returned select, it is not returning all the columns cause of the CLOB data type.
I think your function should be this:
create or replace FUNCTION build_select (
p_table_name IN VARCHAR2
)
RETURN VARCHAR2
AS
l_ret VARCHAR2 (32767);
BEGIN
FOR eachcol IN ( SELECT column_name, data_type
FROM all_tab_cols
WHERE table_name = p_table_name
ORDER BY column_id)
LOOP
IF eachcol.data_type = 'CLOB' THEN
l_ret := l_ret || 'dbms_lob.substr( '||eachcol.column_name||', 3000, 1 ),';
ELSE
l_ret := l_ret || eachcol.column_name||',';
END IF;
END LOOP;
IF l_ret IS NULL
THEN
raise_application_error (-20001, 'table ' || p_table_name || ' not found');
END IF;
l_ret := 'select ' || regexp_replace(l_ret, ',$', NULL) || ' from ' || p_table_name || ';';
RETURN l_ret;
END build_select;
Note, ALL_TAB_COLS selects also system-generated hidden columns and invisible columns which could be a problem. Query ALL_TAB_COLUMNS if you like to filter them.
I have a pl/sql query and I want it's output to be sent in email in CSV format straightaway. I have no directory to first create and save a CSV file and then pick it up to send as an attachment.
Please help with your inputs as I am not able to get away.
Regards,
Sachin
Finally figured out a solution with the help of pointers received and providing the same to further help in case someone else needs in future.
My problem was that I was mostly seeing the examples where i could either save the file on a directory or pick the file from a directory to send as an attchment but I had no provision of directory and I wanted query result to be put in CSV and sent in email dynamically. So here is the complete solution.
CREATE OR REPLACE PROCEDURE SEND_CSV_ATTACHMENT AS
v_sender VARCHAR2(130);
v_recipients VARCHAR2(4000);
v_cc VARCHAR2(4000);
v_bcc VARCHAR2(2000);
v_subj VARCHAR2(200);
v_msg CLOB;
v_mime VARCHAR2(40);
v_tbl VARCHAR2(20000);
c_cr_lf CONSTANT CHAR (2) := (CHR (13) || CHR (10)); -- Carriage Return/Line Feed characters for formatting text emails
v_loop_count PLS_INTEGER := 0;
v_attachment CLOB;
v_block_qry VARCHAR2(3000);
v_block_row VARCHAR2(6000);
TYPE bl_cur IS REF CURSOR;
v_result bl_cur;
v_rowcount NUMBER;
errMsg VARCHAR2(15000);
BEGIN
v_sender := 'somesender#xyzcommunications.com';
SELECT NVL(EMAIL_LIST, 'someone#abcd.com')
FROM
(
SELECT LISTAGG(EMAIL_ID, ',') WITHIN GROUP (ORDER BY EMAIL_ID) AS EMAIL_LIST FROM RECIPEINTS_TABLE WHERE SEND_TO = 1 AND IS_ACTIVE = 1
);
SELECT NVL(EMAIL_LIST, 'someone#abcd.com')
FROM
(
SELECT LISTAGG(EMAIL_ID, ',') WITHIN GROUP (ORDER BY EMAIL_ID) AS EMAIL_LIST FROM RECIPEINTS_TABLE WHERE SEND_CC = 1 AND IS_ACTIVE = 1
);
v_bcc := 'someone#abcd.com';
-- Generate attachment - Begin
v_attachment := '"COL1", "COL2"' || CHR(13) || CHR(10);
v_block_qry := 'SELECT ''"'' || COL1 || ''", "'' || COL2 || ''"'' AS ROWTXT
FROM MY_TABLE';
OPEN v_result FOR v_block_qry;
LOOP
v_rowcount := v_result%ROWCOUNT;
FETCH v_result INTO v_block_row;
EXIT WHEN v_result%NOTFOUND;
v_attachment := v_attachment || v_block_row || chr(13) || chr(10);
END LOOP;
CLOSE v_result;
-- Generate attachment - End
v_subj:= 'MAIL_SUBJECT ' || TO_CHAR(TRUNC(SYSDATE-1), 'YYYY-MM-DD');
UTL_MAIL.send_attach_varchar2(sender => v_sender,
recipients => v_recipients,
cc => v_cc,
bcc => v_bcc,
subject => v_subj,
message => v_msg,
mime_type => 'text/html; charset=us-ascii', -- send html e-mail
attachment => v_attachment,
att_inline => FALSE,
att_filename => 'Change_Report' || TO_CHAR(TRUNC(SYSDATE-1), 'YYYY-MM-DD') || '.csv');
EXCEPTION
WHEN OTHERS THEN
errMsg := SQLERRM;
SEND_MAIL_HTML ('someone#abcd.com', NULL, NULL, errMsg, 'SEND_MAIL ERROR: ' || errMsg);
END SEND_CSV_ATTACHMENT;
You may create such a procedure :
create or replace procedure prFileSend is
v_mail_owner varchar2(100):='myname#someComp.com';
v_url varchar2(4000);
v_rep varchar2(4000);
delimiter varchar2(1) := chr(38);
begin
for c in ( select * from myTable )
loop
begin
v_url := 'http://www.mycompany.com/einfo/default.aspx?email='||c.email || delimiter || 'p1=' || c.col1 || delimiter ||'p2='||c.col2;
v_rep := utl_http.request(utl_url.escape(v_url, false,'ISO-8859-9'));
end;
end loop;
exception
when others then
prErrorMsgSend(v_mail_owner,'Error : ' || sqlerrm); -- a function like this one which sends an error message back to you.
end;
and create a scheduler job
begin
dbms_scheduler.create_job (
job_name => 'jbFileSend ',
job_type => 'STORED_PROCEDURE',
job_action => 'prFileSend',
start_date => '22-jan-2018 09:00:00 am',
repeat_interval => 'FREQ=DAILY; INTERVAL=1',
comments => 'Sending Every day'
enabled => true);
end;
working every day as an example.
This is the frist time that I am going to use dbms_job.submit.
The following piece of code doesn't work:
declare
i_job_no BINARY_INTEGER;
begin
dbms_job.submit(JOB => i_job_no, what => 'declare x number; begin x := f_threads(''my_program'', '|| 6058883 ||' , '|| 2 || '); end;', next_date => sysdate);
dbms_output.put_line(i_job_no);
end;
but the same thing works fine with execute immediate. Can anyone help?!
> declare
i_job_no BINARY_INTEGER;
begin
execute immediate 'declare x number; begin x := f_threads(''my_program'', '|| 6058883 ||' , '|| 2 || '); end;';
end;
thanks!
in this way your pl/sql block will work:
declare
i_job_no BINARY_INTEGER;
begin
dbms_job.submit(JOB => i_job_no, what => 'declare x number; begin x := f_threads(''my_program'', '|| 6058883 ||' , '|| 2 || '); end;', next_date => sysdate);
dbms_output.put_line(i_job_no);
commit;
end;
You are missing a commit in you code
Regards
Giova
try this:
declare
i_job_no BINARY_INTEGER;
begin
dbms_job.submit(JOB => i_job_no, what => 'declare x number; begin x := f_threads(''my_program'', '|| 6058883 ||' , '|| 2 || '); end;', next_date => sysdate);
dbms_output.put_line(i_job_no);
commit;
dbms_job.run(i_job_no);
end;