Oracle SQL Function selecting output - oracle

I am not so used to pipelined functions in Oracle. I worked a lot with Sybase, and MS SQL Server, but Oracle is more or less new to me.
I am using a function from a colleague who left a while ago.
This function return something, if I am not totally wrong:
return ty_CouponTypes_tab pipelined is
V_CT varchar(3);
V_PST varchar(5);
I created a view and iterate over this view with a cursor and pass all the columns to the function, but how can I get the result of this function?
This is what I do not understand.
This is my cursor
set serveroutput on format wrapped;
declare
cursor cCur is select * from VW_PRE_WHITELIST;
begin
for vCurData in cCur
loop
dbms_output.put_line(vCurData.MAT_NAME || ' ' || vCurData.DST_SKONTRO || ' ' || vCurData.DST_ZINSART || ' ' || vCurData.UND_TYP || ' ' || vCurData.DZU_RZ_ERWARTET || ' ' || vCurData.DST_ERSTZINS || ' ' || vCurData.CNT);
select a.* FROM FN_COUPONTYPES(vCurData.MAT_NAME, vCurData.DST_SKONTRO, vCurData.DST_ZINSART, vCurData.UND_TYP, vCurData.DZU_RZ_ERWARTET, vCurData.DST_ERSTZINS, vCurData.CNT) a;
end loop;
end;
Thanks for helping me in advance!

Related

Oracle Apex : How to execute procedure and display the results on a page

I have a procedure that dynamically takes application id as input and displays the result as per application id.
So if :
exec get_app_data(11);
Result would be:
A B C
1 2 3
1 2 3
And if:
exec get_app_data(12);
D E F
1 2 3
1 2 3
So basically it caters the requirement of dynamically changing column headers and displaying dynamic views.
Now how do i add this procedure to oracle apex page?
I understand it would be first added as a page process for execution, but how do i display the results also since the results are dynamic and at runtime?
EDIT: For further clarity this is the procedure which is being executed:
Consider using a region of type Classic Report, where its source is based on a PL/SQL Function Body Returning SQL Query.
You would then simplify your code by removing the cursor stuff and have the parameter be based on a page item. Perhaps something like this:
declare
l_query varchar2(4000);
begin
SELECT 'SELECT *' || CHR(10) ||
' FROM DATA_VALUE' || CHR(10) ||
' PIVOT(' || CHR(10) ||
' MAX(VAL)' || CHR(10) ||
' FOR SEQ IN (' || CHR(10) ||
' ' || LISTAGG(
SEQ || ' "' || LABEL || '"',
',' || CHR(10) ||' '
)
WITHIN GROUP(ORDER BY SEQ) || CHR(10) ||
' )' || CHR(10) ||
' )' || CHR(10) ||
' WHERE APP_ID = ' || APP_ID
INTO l_query
FROM DATA_HEADER
WHERE APP_ID = :P1_APP_ID
GROUP BY APP_ID;
return l_query;
end;

Oracle Dynamic Cursor - ORA-00936 missing expression

I need to use a dynamic cursor in my procedure which receive values from another cursor.
When I run this procedure I got ORA-00936 missing expression.
I put this select from cursor into dbms_output to see it is correct and it was.
This is the code :
BEGIN
OPEN dsa_tables;
LOOP
FETCH dsa_tables INTO
v_owner,
v_table_name,
v_column_name,
v_comments,
v_tech_date;
EXIT WHEN dsa_tables%notfound;
v_table_all := dbms_assert.sql_object_name(v_owner
|| '.'
|| v_table_name);
-- with this cursor is the problem
OPEN count_date FOR ' SELECT '
|| v_column_name
|| ','
|| ' COUNT('
|| v_column_name
|| ') FROM '
||v_table_all
|| ' GROUP BY '
|| v_column_name;
LOOP
FETCH count_date INTO
v_date,
v_count;
EXIT WHEN count_date%notfound;
END LOOP;
CLOSE count_date;
END LOOP;
CLOSE dsa_tables;
END;
/
You likely have v_column_name set to NULL.
I've already checked it and there is no NULL im this column.

Best strategy to reset Oracle sequence monthly

I'm looking for the best strategy to reset a sequence which is used to generate unique keys. These keys are build using a prefix value, also generated by a combination of month and year values, like the following example:
2020060100000001 - Year(4d)Month(2d)Sequence(8d)
The sequence value must be restarted at the first second of each new month.
Is there any Oracle event that allows calling a function or procedure based in this situation to do this job?
Can anyone help me with opinions and experiences?
Thanks a lot!
Rodrigo
If you really want to set the value of a sequence you can use something like the following:
PROCEDURE SET_SEQUENCE(pinSequence_owner IN VARCHAR2,
pinSequence_name IN VARCHAR2,
pinNew_next_value IN NUMBER,
pinDebug IN BOOLEAN := FALSE)
IS
strSQL VARCHAR2(4000);
nNext_number NUMBER;
nOriginal_increment NUMBER;
nNew_nextval NUMBER;
nNew_last_number NUMBER;
BEGIN
strSQL := 'SELECT s.LAST_NUMBER, INCREMENT_BY ' ||
'FROM DBA_SEQUENCES s ' ||
'WHERE s.SEQUENCE_OWNER = ''' || pinSequence_owner || ''' AND ' ||
's.SEQUENCE_NAME = ''' || pinSequence_name || '''';
EXECUTE IMMEDIATE strSQL INTO nNext_number, nOriginal_increment;
-- Note that DBA_SEQUENCES.LAST_NUMBER represents the *next* number which will be
-- returned by a call to NEXTVAL.
IF pinNew_next_value NOT IN (nNext_number-1, nNext_number)
THEN
strSQL := 'ALTER SEQUENCE ' || pinSequence_owner || '.' || pinSequence_name ||
' INCREMENT BY ' || TO_CHAR(pinNew_next_value - nNext_number) || ' NOCACHE';
EXECUTE IMMEDIATE strSQL;
strSQL := 'SELECT ' || pinSequence_owner || '.' || pinSequence_name || '.NEXTVAL FROM DUAL';
EXECUTE IMMEDIATE strSQL INTO nNew_nextval;
strSQL := 'ALTER SEQUENCE ' || pinSequence_owner || '.' || pinSequence_name ||
' INCREMENT BY ' || nOriginal_increment || ' NOCACHE';
EXECUTE IMMEDIATE strSQL;
strSQL := 'SELECT s.LAST_NUMBER FROM DBA_SEQUENCES s WHERE s.SEQUENCE_OWNER = ''' || pinSequence_owner ||
''' AND s.SEQUENCE_NAME = ''' || pinSequence_name || '''';
EXECUTE IMMEDIATE strSQL INTO nNew_last_number;
END IF;
END SET_SEQUENCE;
Resetting sequence every month is not a valid approach. Basically you are violating the utilization of sequence. From your question i could understand, you wanted to append year and month to your column. In this case you can simple concatenate while inserting,
year||month||sequence_name.nextval
Eg: 2020||02||sequence_name.nextval
If you still wanted to reset, you can create a trigger to reset the sequence every month,

Can a bind variable be concatenated to a dynamic SQL WHERE clause in order to add an AND statement?

I am attempting to add an AND statement to a dynamic WHERE clause using a bind variable and I am receiving the following Oracle error:
ORA-01830: date format picture ends before converting entire input string bind variable
Here is the offending code:
FUNCTION WhereClause RETURN VARCHAR2
IS
BEGIN
where_sql := 'WHERE TRUNC( ' || parm_rec.SRC_DATE_COLUMN || ' ) < ADD_MONTHS( ' ||
'ADD_MONTHS ( TRUNC ( NVL ( :SYS_OFFSET, SYSDATE ) - ( :DAY_OFFSET )), ' ||
'( :MON_OFFSET * :kNEGATIVE ) ), ' ||
'( :YR_OFFSET * ( :kANNUM * :kNEGATIVE ) ) ) ';
RETURN where_sql;
END WhereClause;
PROCEDURE ArchiveSrcDateFilter
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('ArchiveDynamic - ENTER');
IF parm_rec.SRC_DATE_COLUMN IS NULL THEN parm_rec.SRC_DATE_COLUMN := 'NULL';
END IF;
FOR i in tbl_cur
LOOP
where_sql := WhereClause; -- defines the WHERE clause (where_sql) via function, Spec will not return variable to body?
/*** DYNAMIC SQL DECLARATIONS ***/
arc_sql := 'DECLARE ' ||
/*** DYNAMIC %ROWTYPE SELECT ***/
'CURSOR arc_cur IS ' ||
'SELECT * '||
'FROM ' || i.ARC_TABLE_NAME || '; '|| --obtain ARCHIVE ARC_SCHEMA_NAME.ARC_TABLE_NAME
'TYPE arc_cur_type IS TABLE OF arc_cur%ROWTYPE; ' || -- dynamically set archive record cursor %ROWTYPE for BULK COLECT as table collection
'arc_rec arc_cur_type; ' || -- define archive record as TABLE OF cursor.%ROWTYPE
/*** ARCHIVE PARAMETERS CURSOR - SRC_CREATE_DATE IS NOT NULL***/
'CURSOR parm_cur IS '||
'SELECT :seq_val AS ARCHIVE_ID, '||
'A.*, ' ||
'SYSDATE AS ARCHIVE_DATE ' ||
'FROM ' || srcSchemaTable || ' A ' || -- archive SRC_SCHEMA_NAME.SRC_TABLE_NAME (source table not archive table)
where_sql || ' || :ADD_FILTER ' || ' ; ' ||
/*** DYNAMIC SQL STATEMENT BODY ***/
'BEGIN '||
'IF parm_cur%ISOPEN THEN CLOSE parm_cur; ' ||
'END IF; ' ||
'OPEN parm_cur; ' ||
'LOOP ' ||
'FETCH parm_cur ' ||
'BULK COLLECT INTO arc_rec LIMIT 500; ' ||
'EXIT WHEN arc_rec.COUNT = 0; ' ||
'FORALL i IN 1..arc_rec.COUNT ' ||
'INSERT INTO ' || arcTable ||
' VALUES arc_rec( i );' ||
'DBMS_OUTPUT.PUT_LINE( ''ARC_REC_COUNT: '' || arc_rec.COUNT ); ' ||
'END LOOP; ' ||
'CLOSE parm_cur; ' ||
'DBMS_OUTPUT.PUT_LINE(''SUCCESS...''); '||
'END; ';
DBMS_OUTPUT.PUT_LINE('ArchiveDynamic - INSIDE LOOP: ' || arc_sql );
EXECUTE IMMEDIATE arc_sql
USING seq_val, parm_rec.SYS_OFFSET, parm_rec.DAY_OFFSET, parm_rec.MON_OFFSET, kNEGATIVE, parm_rec.YR_OFFSET, kANNUM, parm_rec.ADD_FILTER;
END LOOP;
END ArchiveSrcDateFilter;
This is the specific piece of code in the ArchiveSrcFilter procedure where the :ADD_FILTER bind variable is located (Note: I have attempted different concatenation iterations for the bind variable without success this was simply my last attempt before posting the issue here) :
'CURSOR parm_cur IS '||
'SELECT :seq_val AS ARCHIVE_ID, '||
'A.*, ' ||
'SYSDATE AS ARCHIVE_DATE ' ||
'FROM ' || srcSchemaTable || ' A ' ||
where_sql || ' || :ADD_FILTER ' || ' ; ' ||
And the EXECUTE IMMEDIATE USING with the last parameter as the bind:
EXECUTE IMMEDIATE arc_sql
USING seq_val, parm_rec.SYS_OFFSET, parm_rec.DAY_OFFSET, parm_rec.MON_OFFSET, kNEGATIVE, parm_rec.YR_OFFSET, kANNUM, parm_rec.ADD_FILTER;
the parm_rec.ADD_FILTER = AND STATUS = 1062
Is it possible to do what I am attempting by concatenating the bind to the where?
I don't understand the odd error message I am receiving given that the code executes without exception if I concatenate the parm_rec.ADD_FILTER object variable or hard code the AND STATUS = 1062.
I can concatenate the parm_rec.ADD_FILTER in place of the bind variable and the code executes without exception, but I have been unsuccessful in attempts to get the bind variable to work.
I'm grateful for any suggestions and/or insight.
Thanks!
No. Column names (i.e. STATUS) and operators (i.e. AND, =) can never be resolved from bind variables.

Efficient query to find invalid number's in varchar column

I have already asked almost the same question before:
Finding non-numeric values in varchar column
And I received some great answer's and idea's to make not only fix the issue in my query but also make it much more efficient.
Old Query:
Select * From Table_Name
Where
(NOT REGEXP_LIKE(COLUMN_NAME, '^-?[0-9.]+$')
OR
LENGTH(Function_To_Fetch_Left_Component(COLUMN_NAME)) > (Precision-Scale)
OR
LENGTH(Column_Name) - LENGTH(REPLACE(Column_Name,'.','')) > 1)
New Query:
Select * From Table_Name
WHERE (Translate(column_name,'x0123456789-.','x') is not null
OR column_name = '.'
OR column_name = '-'
OR column_name = '-.'
OR Instr(column_name,'-') > 1
OR column_name like '%-%-%'
OR column_name like '%.%.%'
OR Instr(column_name||'.','.')-1 > (precision-scale) ) ;
Known limitations which are okay:
1.) Doesn't handle scientific notation. Its by design as I want to reject those.
2.) Doesn't check total precision (decimal component) however as while inserting oracle itself round's it off I am fine with it.
3.) Doesn't check for leading zero's.
Please help to see if the above query cover's everything and I haven't missing anything.
Another great solution by one Stackoverflow member however increased execution time by 2.5 times:
Function:
CREATE OR REPLACE function temp_is_number(p_test_value varchar2,
p_scale NUMBER,
p_precision NUMBER) return varchar2 is
l_result varchar2(1);
begin
execute immediate 'DECLARE l_number NUMBER; ' ||
'l_test_number NUMBER(' || p_precision || ',' || p_scale || '); ' ||
'BEGIN ' ||
' l_number := cast(:b1 as number); ' ||
' l_test_number := cast(:b1 as number); ' ||
' IF (l_number = l_test_number) THEN ' ||
' :b2 := ''Y''; ' ||
' ELSE ' ||
' :b2 := ''N''; ' ||
' END IF; ' ||
'EXCEPTION ' ||
' WHEN OTHERS THEN ' ||
' :b2 := ''N''; ' ||
'END;'
using in p_test_value, out l_result;
return l_result;
end;
/
Select Count(1) from Table_Name Where temp_is_number (Column_Name,scale,precision) = 'N';

Resources