I am using Oracle APEX 4.2. I want to implement a search function in my classic report. I have a working code that retrieve data and the search function works perfectly. But when I want to use an order by clause inside that code I get "no data found" how can I implement an order by clause into this code so my report will be sorted correctly and the search function will still work correctly.
Here is the working code below that allows you to search the classic report:
declare
a_query varchar2(5000);
this_strin varchar2(50);
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''||
:P3_DATA_VERSION || '''';
if :P3_SEARCH_NUMBER is not null then
if instr(:P3_SEARCH_NUMBER, '%') > 0 then
this_strin := :P3_SEARCH_NUMBER;
else
this_strin := '%'||:P3_SEARCH_NUMBER||'%';
end if;
a_query := a_query||chr(10)||
' and flight_nmbr like '''|| upper(this_strin) ||'''';
end if;
return a_query;
end;
Here is same piece of code that does says "no data found" when I add the order by clause to the query:
declare
a_query varchar2(5000);
this_strin varchar2(50);
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''||
'order by sequence_nmbr 1'|| ------------------Order by clause
:P3_DATA_VERSION || '''';
if :P3_SEARCH_NUMBER is not null then
if instr(:P3_SEARCH_NUMBER, '%') > 0 then
this_strin := :P3_SEARCH_NUMBER;
else
this_strin := '%'||:P3_SEARCH_NUMBER||'%';
end if;
a_query := a_query||chr(10)||
' and flight_nmbr like '''|| upper(this_strin) ||'''';
end if;
return a_query;
end;
Obviously, your problem is here:
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''|| -- double qoute!!!
'order by sequence_nmbr 1'|| ------------------Order by clause
:P3_DATA_VERSION || '''';
Due to that redundant double quote, your resulting query looks like this:
select flight_nmbr, sequence_nmbr
from flights
where sequence_nmbr >= 0
and data_version_name = 'order by sequence_nmbr 1<value of P3_DATA_VERSION item>';
As soon as the table has no value order by sequence_nmbr 1 in the column data_version_name, the query returns no rows.
The second problem you will encounter when you'll fix this one is here:
if :P3_SEARCH_NUMBER is not null then
When this statement will be true, you will get a query where the condition and flight_nmbr like ... stands after the ORDER BY clause.
By the way, I would recommend you write a simple query for the report. Generating SQL dynamically leads to such errors and costs you a performance decrease also.
Not related to your question, but - why don't you switch to interactive report? It offers much more than a classic report, don't you think?
As of your problem: if you look at query that fails, its SELECT looks like this (I've removed single quotes):
and data_version_name = ||
order by sequence_nmbr 1 || ------------------Order by clause
:P3_DATA_VERSION ||
and flight_nmbr like upper(this_strin)
Either you didn't post actual code, or this is generally wrong - I hope you see what is wrong here. ORDER BY should be the last clause. Besides, what's that "1" doing at the end of the ORDER BY?
I'd suggest you to first display contents of the A_QUERY, check whether it works OK (in SQL*Plus, TOAD, SQL Developer or any other tool you use), and - once you're satisfied with it - let it work in Apex.
Related
I am creating function in postgresql to update table. when I ran single function it works fine but I use same query inside function it wont works.
update house1 SET calendar=
'H'||' '||house_num::text||' '||left(to_char(sdate, 'Mon'),2) ||' to ' || to_char(sdate, 'DD') ||to_char(rdate, 'Mon-DD')
where id=1
Inside function I wrote following query
begin
execute
'UPDATE house1 SET calendar = '
||quote_nullable( 'H')||' '||house_num||' '||left(to_char(sdate, 'Mon'),2) ||' to ' || to_char(sdate, 'DD') ||to_char(rdate, 'Mon-DD')
|| ' WHERE' || 'stage'
'>=' || quote_nullable(0) ;
END
It generates following error
ERROR: column "house_num" does not exist.
Please help me
Why do you use the execute statement in function?
You can use update statement directly in function (When using the execute statement if you need to build dynamic query)
create or replace function function_name()
returns void
language plpgsql
as
$$
begin
update house1 SET calendar=
'H'||' '||house_num::text||' '||left(to_char(sdate, 'Mon'),2) ||' to ' || to_char(sdate, 'DD') ||to_char(rdate, 'Mon-DD')
where stage >= 0;
end;
$$;
select function_name();
I created the following PL/SQL anonymous block. The cursor below retrieves data from the select statement:
select mod_benutzer, count(*)
from dok_auspraegung
where parent_objekt_id = 1093
group by mod_benutzer;
This statement displays exactly two records:
DDMS_USER | 8
HU2MAMU | 14
But when I want to display these two records by cursor, it displays "HU2MAMU|14" two times like below:
Modifications:
DDMS_USER, 8x
HU2MAMU, 14x
HU2MAMU, 14x
declare
my_exception_1 exception;
var_parent_objekt_id dok_auspraegung.parent_objekt_id%TYPE := 1093;
var_date varchar(30);
var_mod_benutzer varchar2(10);
var_benutzer_modifs number;
cursor cursor_dok_auspraegung
is select mod_benutzer, count(*) from dok_auspraegung
where parent_objekt_id = 10935797565
group by mod_benutzer;
begin
select distinct to_char(mod_datum,'YYYY-MON-DD') into var_date from dok_auspraegung where parent_objekt_id = var_parent_objekt_id;
IF var_date is not null THEN
dbms_output.put_line('Parent Object ID' || ': ' || var_parent_objekt_id);
dbms_output.put_line('Date: ' || ' ' || var_date);
ELSE RAISE my_exception_1;
END IF;
open cursor_dok_auspraegung;
dbms_output.put_line('Modifications:');
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
exit when cursor_dok_auspraegung%notfound;
end loop;
dbms_output.put_line(cursor_dok_auspraegung%rowcount);
close cursor_dok_auspraegung;
exception
when NO_DATA_FOUND then
dbms_output.put_line('Parent Object ID not found!');
when my_exception_1 then
dbms_output.put_line('');
end;
What is the reason of that?
Because exiting from the cursor occurs after printing the value of the variables in the current case, this repeats the last value to be printed. So, it should occur before printing as follows
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
exit when cursor_dok_auspraegung%notfound;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
end loop;
I am executing a query in PL / SQL in version 7 and version 14, with a function created by me, and both bring me some results, the rest bring 0.
However, when executing the same query in Oracle SQL Developer, the query brings all the results correctly.
I executed the procedure through PL / SQL and Oracle SQL Developer as well, but then none brought me the right result, all the lines were left as "0".
I can't find the problem at all, even on Google.
Basically, the function multiplies the number of rows by columns that start with "ID_", as shown below.
Function:
CREATE OR REPLACE FUNCTION DS_FUNCESP.FNBIGB_CheckDataCells
(pOwn IN VARCHAR2,
pTab IN VARCHAR2)
RETURN NUMBER
IS
v_Qtd NUMBER;
v_str VARCHAR2(2000);
BEGIN
v_Qtd := 1;
v_str := ' SELECT
SUM((SELECT COUNT(1) AS QTY_ROWS FROM ' || pOwn || '.' || pTab || ' d WHERE d.LINORIGEM <> ''CARGA MANUAL'')) AS QTY_DATA
FROM DW_FUNCESP.D_BI_COLUMNS a
LEFT JOIN
DW_FUNCESP.D_BI_TABLES b
ON a.ID_TABLE = b.ID_TABLE
AND a.ID_OWNER = b.ID_OWNER
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON a.ID_OWNER = c.ID_OWNER
WHERE b.NM_TABLE = ''' || pTab || '''
AND a.IN_PRIMARYKEY = ''NAO''
AND SUBSTR(a.NM_COLUMN,1,3) = ''ID_'' ';
DBMS_OUTPUT.put_line(v_str);
EXECUTE IMMEDIATE v_str into v_Qtd ;
return (v_Qtd);
EXCEPTION WHEN OTHERS THEN
RETURN 0;
END FNBIGB_CheckDataCells;
Select statement:
SELECT
c.NM_OWNER ,
b.NM_TABLE ,
DS_FUNCESP.FNBIGB_CHECKDATACELLS(c.NM_OWNER, b.NM_TABLE) AS QTY_DATA
FROM DW_FUNCESP.D_BI_TABLES b
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON b.ID_OWNER = c.ID_OWNER;
Results from PL/SQL:
Results from Oracle SQL Developer:
Clearly we can see the difference from any row, the right one is the Oracle SQL Developer. So I'd like to know what is the problem, how to fix, because the procedure is adding "0" to all the rows, no matter where I run.
Reading those examples from WHEN OTHERS - A Bug, thanks to #Lalit Kumar B for that, I changed:
EXCEPTION WHEN OTHERS THEN
RETURN 0;
To:
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Message: '||SQLERRM);
RAISE;
To find out the problem, and thanks for that I found that it was trying to count from a table where it doesn't exist anymore.
So I using an error handling as below, from #Jeffrey Kemp
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
Also, thanks for #Belayer, my code was the problem, agreed on that. Also, executing on both softwares, made me even more confused. I'll read also that documentation for sure.
I have created a package with two procedures and two cursors in it, but while executing the procedure, it is executed successful, but same record executed multiple times and a buffer overflow occurred.
I also tried removing the loop from the cursor but for 1 record that will be fine and for multiple record it won't work as expected.
EXPECTED
I just need to remove multiple execution of same record from the procedure where i am getting multiple execution of same record
for single procedure and single cursor it is working properly but for multiple cursor and multiple procedure i am getting problem here which caused buffer overflow too where i need different record
Is there any alternative way that I can fix the problem ?
CREATE OR REPLACE PACKAGE test.report AS
PROCEDURE distribution (
code_in IN user.test.code%TYPE,
fromdate date,
todate date
);
PROCEDURE tdvalue (
id IN user.test.custid%TYPE
);
END report;
/
Package Body
CREATE OR REPLACE PACKAGE BODY test.report as
----------VARIABLE DECLARATION----------------
code_in user.test.code%TYPE;
custidin user.test.custid%TYPE;
fromdate DATE;
todate DATE;
diff number(17,2);
---------------CURSOR DECLARATION--------------
CURSOR td_data(code_in user.test.code%TYPE,
fromdate date,
todate date
) IS
( SELECT
test.code,
COUNT(test.code) AS count,
SUM(test2.Deposit_amount) AS total,
test.currency
FROM
user.test2
JOIN user.test ON test2.acid = test.acid
WHERE
user.test2.open_effective_date BETWEEN TO_DATE(fromdate, 'dd-mm-yyyy') AND TO_DATE(todate, 'dd-mm-yyyy')
and
user.test.code = code_in
GROUP BY
test.code,test.currency
);
td__data td_data%rowtype;
CURSOR C_DATA(custidin user.test.custid%TYPE) IS SELECT
test.custid,
test2.id,
TO_DATE(test2.initial_date, 'dd-mm-yyyy') - TO_DATE(test2.end_date, 'dd-mm-yyyy') AS noofdays,
round(((test2.deposit_amount *((TO_DATE(test2.initial_date, 'dd-mm-yyyy') - TO_DATE(test2.end_date, 'dd-mm-yyyy'
)) / 365) * test4.interest_rate) / 100), 2) + test2.deposit_amount AS calculated_amount,
SUM(test.flow_amt) + test2.deposit_amount AS system_amount
FROM
user.test
JOIN user.test2 ON test3.entity_id = test2.id
WHERE
test.custid = custidin
GROUP BY
test.custid,
test2.id;
c__data c_data%ROWTYPE;
PROCEDURE distribution
(
code_in IN user.test.code%TYPE,
fromdate in date,
todate in date
)
AS
BEGIN
OPEN td_data(code_in,fromdate,todate);
loop
FETCH td_data INTO td__data;
dbms_output.put_line(td__data.code
|| ' '
|| td__data.count
|| ' '
||td__data.currency
||' '
||td__data.total
);
end loop;
CLOSE td_data;
END distribution;
PROCEDURE tdvalue (
custidin IN user.test.custid%TYPE
)
AS
BEGIN
open c_data(custidin);
fetch c_data into c__data;
loop
diff:= c__data.calculated_amount- c__data.system_amount;
dbms_output.put_line(c__data.custid
|| ' '
|| c__data.noofdays
|| ' '
|| c__data.end_date
|| ' '
|| c__data.initial_date
|| ' '
|| c__data.calculated_amount
||' '
||diff
);
end loop;
close c_data;
END tdvalue;
END report;
/
To run
ALTER SESSION set nls_date_format='dd-mm-yyyy';
SET SERVEROUTPUT ON;
EXEC REPORT.DISTRIBUTION('872328','01-02-2016','08-02-2019');
/
EXEC REPORT.tdvalue('S9292879383SS53');
Buffer overflow - ORU-10027 - happens when the total number of bytes displayed through DBMS_OUTPUT exceeds the size of the serveroutput buffer. The default is only 20000 bytes (who knows why?). Your session is using that default because of how you enable serveroutput. Clearly one record is less than 2000 and you only hit that limit when you run for multiple records.
To fix this try this
SET SERVEROUTPUT ON size unlimited
It's not actually unlimited, but the upper bound is the PGA limit (session memory) and you really shouldn't hit that limit with DBMS_OUTPUT. Apart from anything else who would read all that?
So the other problem with your code - as #piezol points out - is that your loops have no exit points. You should test whether the FETCH actually fetched anything and exit if it didn't:
loop
FETCH td_data INTO td__data;
exit when td_data%notfound;
dbms_output.put_line(td__data.code
|| ' '
|| td__data.count
|| ' '
||td__data.currency
||' '
||td__data.total
);
end loop;
Remembering to do this is just one reason why implicit cursors and cursor for loops are preferred over explicit cursors.
The second cursor loop is even worse because not only does it not have an exist point, the fetch is outside the loop. That's why you have repeated output for the same record.
So let's rewrite this ...
open c_data(custidin);
fetch c_data into c__data; -- should be inside
loop
diff:= c__data.calculated_amount- c__data.system_amount;
… as a cursor for loop:
PROCEDURE tdvalue (
custidin IN user.test.custid%TYPE
)
AS
BEGIN
for c__data in c_data(custidin)
loop
diff:= c__data.calculated_amount- c__data.system_amount;
dbms_output.put_line(c__data.custid
|| ' '
|| c__data.noofdays
|| ' '
|| c__data.end_date
|| ' '
|| c__data.initial_date
|| ' '
|| c__data.calculated_amount
||' '
||diff
);
end loop;
END tdvalue;
No need for OPEN, CLOSE or FETCH, and no need to check when the cursor is exhausted.
In PL/SQL, the preferred mechanism for setting the DBMS_OUTPUT buffer size would be within your procedure. This has the benefit of working in any client tool, such as Java or Toad (though it is still up to the client tool to retrieve the output from DBMS_OUTPUT).
DBMS_Output.ENABLE
Pass in a parameter of NULL for unlimited buffer size.
It would go like this:
BEGIN
DBMS_OUTPUT.ENABLE(NULL);
FOR I IN 1..1000 LOOP
DBMS_OUTPUT.PUT_LINE('The quick red fox jumps over the lazy brown dog.');
END LOOP;
END;
/
Bonus fact:
You can use the other functions and procedures in DBMS_OUTPUT to roll your own if you aren't using SQL*Plus or a DBMS_OUTPUT-savvy tool like Toad.
You can use the GET_LINE or GET_LINES procedures from your client code to get whatever may have been written to DBMS_OUTPUT.
GET_LINE
I have the following codes:
IF nvl(p_value, 0) >= 0 THEN
l_currency_prefix := 'scc.currency_prefix_pos';
l_currency_suffix := 'scc.currency_suffix_pos';
ELSE
l_currency_prefix := 'scc.currency_prefix_neg';
l_currency_suffix := 'scc.currency_suffix_neg';
END IF;
l_query := 'SELECT nvl('||l_currency_prefix||', '')'
||'trim(to_char('||p_value||
',scc.currency_format
,'||'NLS_NUMERIC_CHARACTERS=' || 'scc.decimal_group_separator'||'))'
||'nvl('||l_currency_suffix||', '')
FROM gss.gss_currency_locale scc
WHERE scc.country_code =' ||p_country_code||
'AND scc.currency_code ='|| p_currency_code||
'AND rownum=1';
and here is the dbms output for l_query:
SELECT nvl(scc.currency_prefix_pos, ')trim(to_char(10000,scc.currency_format
,NLS_NUMERIC_CHARACTERS=scc.decimal_group_separator))nvl(scc.currency_suffix_pos, ')
FROM gss.gss_currency_locale scc
WHERE scc.country_code =USAND scc.currency_code =USDAND rownum=1
However, it keep showing an ORA-00933 errors.
I debug these piece of code for few hours and could not find where is the errors.
Could some one please provide some advice on this?
Now some of the problems are obvious. You need something like this:
l_query := 'SELECT nvl('||l_currency_prefix||',
||'trim(to_char('||p_value||
',scc.currency_format || ')' ||
FROM gss.gss_currency_locale scc
WHERE scc.country_code = ''' ||p_country_code|| '''' ||
' AND scc.currency_code = '''|| p_currency_code|| '''' ||
' AND rownum=1';
(I'm not sure if that is 100 percent correct.)
Usually, when creating queries this way, I use replace() instead of direct substitution. Something like:
l_query := 'select nvl(#currency_prefix, trim(#p_value, #currency_format))
from . . . ';
l_query := replace(l_query, '#currency_prefix', l_currency_prefix);
l_query := replace(l_query, '#p_value', p_value);
. . .
I find that this approach makes it much easier to maintain the code and to see what it is doing.