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
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;
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.
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,
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.
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';