Unable to return query output in Apex PL SQL expression - plsql

I am trying to write a following PL/SQL function body for a dynamic action
The purpose of dynamic action is to set value for text area based on input parameters. Way I am trying to do it, is that setting the value into variable for different options
declare
P_NOTE varchar(100); -- derive value
P_WEBSERVER varchar(100); -- derive name
begin
-- for getting the P_NOTE value
select distinct note into P_NOTE from port_mapping where PLATFORM = :P3_PLATFORM and VERSION = :P3_VERSION;
-- for getting web server value
select CONCAT(P_NOTE,CONCAT('https-',:P3_CLIENT)) into P_WEBSERVER from dual order by 1;
if (:P3_PLATFORM = 'Apache') then
return P_WEBSERVER;
end if;
end;
However I am getting error
ORA-06550: line 15, column 5:
PLS-00372: In a procedure, RETURN statement cannot contain an expression
ORA-06550: line 15, column 5:
PL/SQL: Statement ignored
declare
P_NOTE varchar(100);
P_WEBSERVER varchar(100);
I am not sure what I am missing.

(Since you did not post any apex version this explanation deals with version 4.2)
If this -is- a dynamic action and the code you posted is in a true action of type 'Execute PL/SQL Code' then you can not use RETURN. The plsql block is not a function body (close, Mr Kemp!).
If you want to return values from the session state to page items then you need to use the "Page Items to Return" item of the true action.
This will put the session state of the defined page items into the value of the item on the page. This means that you can not use any variable to just put stuff in to be able to return it to the page, but you need to use an actual page item (after all, these are bind variables).
To clarify further, you would not write :
return P_WEBSERVER;
But you'd have to use a page item, say P3_WEBSERVER, and you'll need to create one if it doesn't exist of course:
:P3_WEBSERVER := p_webserver;
Of course you'd need to make sure that the correct value will be in there as you can not shortcircuit as you did in your code sample (p_webserver will usually hold a value even if the platform is not 'Apache') eg:
if (:P3_PLATFORM = 'Apache') then
:P3_WEBSERVER := P_WEBSERVER;
else
:P3_WEBSERVER := NULL;
end if;

Just read error message:
line 15, column 5
So, trouble caused by this line:
return P_WEBSERVER;
return not allowed in PL/SQL blocks, use output parameter to return a value.
Read Tom's answer to find out how to do that.

Related

ORA-06550 & PLS-00103 Errors when setting Oracle APEX item's default value

I am trying to set the default value of an item in Oracle APEX 4.2 by selecting the first value in a table having the specified VIDEO_ID. In the item, under the Default section I have set Default Value Type = PL/SQL EXPRESSION, and in the Default Value block I have entered
SELECT UNIQUE_ALLEGATION_ID
FROM (
SELECT UNIQUE_ALLEGATION_ID
FROM TBL_UNIQUE_ALLEGATION
WHERE VIDEO_ID = :P2_VIDEO_SELECT) A
WHERE ROWNUM <= 1
ORDER BY ROWNUM;
This code works just fine in my Oracle editor (if I replace :P2_VIDEO_SELECT with a value; and I am positive that :P2_VIDEO_SELECT is properly set).
However, when I run the page, I get the following error:
ORA-06550: line 1, column 43: PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:
( - + case mod new not null <an identifier> <a double-quoted delimited-identifier> <a bind variable>
continue avg count current exists max min prior sql stddev sum variance execute forall merge time timestamp interval date
pipe
Remember that Apex attributes that accept SQL or PL/SQL fragments must be executed by the Apex at runtime, and that these must necessarily be embedded in wrapping code that must compile and execute at runtime.
So, for example, a source that is of type "PL/SQL Expression" will probably be executed in something like this:
declare
temp_var varchar2(4000);
begin
temp_var := (
SELECT UNIQUE_ALLEGATION_ID
FROM (
SELECT UNIQUE_ALLEGATION_ID
FROM TBL_UNIQUE_ALLEGATION
WHERE VIDEO_ID = :P2_VIDEO_SELECT) A
WHERE ROWNUM <= 1
ORDER BY ROWNUM
);
--use temp_var somewhere
end;
Obviously, the above code is not expected to work, which is why you're seeing an error like ORA-06550.

Passing variable to a Select query in Oracle

I am working on Oracle 11g Db, Having trouble on writing Oracle syntax.
I am trying to pass a number variable to my select query and populate the select query to a cursor.
Declare yr_nr NUMBER;
Begin
yr_nr := 2014;
SELECT DCD.CCY ID, DCD.CCYCDDSC DSC
FROM CCYDCD DCD, CCYEXC EXC
WHERE DCD.CCY = EXC.CCY
AND EXC.YEARNR = yr_nr
End
This select query returns 80 records. How to rewrite this syntax.
Ok, so what you have here is an anonymous block and everything that happens in the block stays in that block. Kinda like Vegas.
In other words there is nothing to handle the result set from your query. When you do this:
declare
[varName] [type]
begin
select foo from bar where column = var ; <--- this has no place to go!
end
When you are at an sqlPlus prompt, sqlPlus has a default record set handler which then processes the returned record set and prints it to the screen.
When you use any third party tool like JDBC or Oracle's own OCI library those provide a record set handler then parse them to you with the appropriate calls to get the data, e.g.:
rs.getInteger([query],[column] ) //which returns the specific value.
That anonymous block is essentially a stored procedure. So you have to have something to do with the result set. This is the cause of the missing "into" error you are getting.
If on the other hand you did something like:
declare
[varName] [type]
result number ;
begin
select count(foo) into result from bar where column = var ;
end
The variable result would have the value of 80 since that is the number of records fetched.
declare
[varName] [type]
cursor thisCursor(p1 in number ) is select foo from bar where column = p1 ;
begin
for rec in thisCursor(varName) loop
If rec.column = [some value] then
doSomething
end if ;
end loop ;
end
Do this would allow you to do something with the result set.

PLS-00487 Error-Invalid reference to Variable 'CHAR'

I'm designing a function that is part of a larger package. The function is intended to take a District Code and return a collection of unique IDs for 10-15 stores that are assigned to that district. The function is intended to return a collection that can be queried like a table, i.e., using the TABLE function in a SQL statement.
I've created the following Types:
Schema Level type:
create or replace TYPE HDT_CORE_ORGIDS AS TABLE OF CHAR(20);
and a Type inside the Package
TYPE CORE_ORGIDS IS TABLE OF CHAR(20) INDEX BY BINARY_INTEGER;
Here's the function code:
FUNCTION FindDistrictOrgs(
ParamOrgCode VARCHAR2
)
RETURN HDT_CORE_ORGIDS
AS
ReturnOrgs HDT_CORE_ORGIDS := HDT_CORE_ORGIDS();
FDOTemp HDT_CORE_MAIN.CORE_ORGIDS;
i BINARY_INTEGER := 0;
CURSOR FDOCurr IS
SELECT org.id AS OrgID
FROM tp2.tpt_company org
WHERE LEVEL = 2
START WITH org.name = ParamOrgCode
CONNECT BY PRIOR org.id = org.parent_id;
BEGIN
OPEN FDOCurr;
LOOP
i := i +1;
FETCH FDOCurr INTO FDOTemp(i);
EXIT WHEN FDOCurr%NOTFOUND;
END LOOP;
IF FDOTemp.EXISTS(FDOTemp.FIRST) THEN
ReturnOrgs.EXTEND(FDOTemp.LAST);
FOR x IN FDOTemp.FIRST .. FDOTemp.LAST LOOP
ReturnOrgs(x) := FDOTemp(x).OrgID;
END LOOP;
END IF;
CLOSE FDOCurr;
RETURN ReturnOrgs;
END FindDistrictOrgs ;
I'm getting the PLS-00487:Invalid Reference to variable 'CHAR' at the line:
ReturnOrgs(x) := FDOTemp(x).OrgID;
I've double-checked at the value returned by the SQL (the org.id AS OrgID) is of the CHAR(20 BYTE) datatype.
So...what's causing the error?
Any help is appreciated! :)
OrgID is the alias you gave the column in your cursor, it has no meaning to the collection. Since both collections are of simple types you should just be doing:
ReturnOrgs(x) := FDOTemp(x);
The syntax you're using is implying FDOTemp is a collection of objects and you're trying to reference the OrgID attribute of an object; but since CHAR isn't an object type, this errors. The error message even makes some sense when viewed like that, though it's not terribly helpful if you don't already know what's wrong... and not entirely helpful when you do.
Incidentally, you could use a bulk collect to populate the collection without the cursor or loops, or the extra collection:
SELECT org.id
BULK COLLECT INTO ReturnOrgs
FROM tp2.tpt_company org
WHERE LEVEL = 2
START WITH org.name = ParamOrgCode
CONNECT BY PRIOR org.id = org.parent_id;
RETURN ReturnOrgs;

Debugging a function with table type as input parameter

Can anybody let me know how can i debug a functions with table type as input parameter and this function returns a table type pipelined.
Please see below details.When i try to test the function it creates below anonymous block but when i click on debug button it gives error:
Anonymous block:
declare
-- Non-scalar parameters require additional processing
result t_bmk_q;
pit_srch_str t_parm;
begin
-- Call the function
result := f_bmk_srch(pit_srch_str => pit_srch_str,
piv_op => 'ALL');
end;
---f_bmk_q function returns table type t_bmk_q pipelined
defintions:
==============
t_bmk_q --->table type
t_bmk_q is TABLE OF r_bmk_q -->object of some attributes.
pit_srch_str ---> is parameter of type t_parm which is table type of r_parm
--plz see def of r_parm:
CREATE OR REPLACE TYPE r_parm AS OBJECT
(
p_abc varchar2(200)
,p_new_val varchar2(2000)
,CONSTRUCTOR FUNCTION r_parm
(
p_abc varchar2
,p_new_val varchar2
) RETURN SELF AS RESULT
);
Example:I have below sample values to test and debug:
r_parm('TAB1.VALUE','123321123')
Thanks
Rajesh
It seems you are using a PL/SQL Developer Test Window to run the tests. I recognise the comment Non-scalar parameters require additional processing.
PL/SQL Developer's Test Window doesn't handle pipelined functions too well.
You are best off removing the result variable and wrapping the function call in open :cursor for select * from table(...). Add a variable named cursor of type Cursor to the variables list below the window.
To populate the input table, you can simply 'call' the table type, passing each row in the table as a separate argument. For example,
t_parm(r_parm(...), r_parm(...), r_parm(...))
You can add as many rows to the table as you like this way.
Putting both of these changes together, we have something like the following:
declare
pit_srch_str t_parm;
begin
-- Create input table.
pit_srch_str := t_parm(
r_parm('TAB1.VALUE','123321123'),
r_parm('TAB2.VALUE','456597646')
);
-- Call the function
open :cursor for select * from table(f_bmk_srch(pit_srch_str => pit_srch_str,
piv_op => 'ALL'));
end;
/
Once you've run the function, you can get the results from the cursor variable (use the ... button at the far right).

Return ref_cursor from for loop of cursor object

I am trying to get a ref_cursor to be assigned to a variable inside a for loop then returned at the end of a function. The loop in going through a local cursor if it gets more than 1 result.
I have noted where the error occurs in the code. I am not sure how to create a loop where i can get a ref_cursor for the current point in the loop, assign it to a variable and then return it to the function. Could someone someone help me figure out how to do that? Below is my i-th attempt at logic based of reading around the google searches.
The error is "PLS-00382: expression is of wrong type" and i know that i obviously am not assigning the correct variably type based on this error but the code below with the error is an illustration of what I want to do and what I need help accomplishing.
FUNCTION GET_PARCEL(p_lat in number, p_long in number) return sys_refcursor
IS
v_distance number(10) := 100000000;
v_shortest_dist number(10) := v_distance;
v_centroid SDO_GEOMETRY;
v_rc_ref_cursor sys_refcursor;
v_ref_geom SDO_GEOMETRY := mdsys.SDO_GEOMETRY(2001, 8311, NULL, SDO_ELEM_INFO_ARRAY(1, 1, 1), SDO_ORDINATE_ARRAY(120.3214, -10.7088));
cursor query_cursor is select * from PARCEL_TABLE where code = 20134;
BEGIN
for query_row in query_cursor loop
v_centroid := SDO_GEOM.SDO_CENTROID(query_row.geometry, 0.05);
IF (v_centroid is not null) then
v_distance := SDO_GEOM.SDO_DISTANCE(v_centroid, v_ref_geom, 0.05);
IF v_distance < v_shortest_dist THEN
v_shortest_dist := v_distance;
v_rc_ref_cursor := query_row; -- Error on this line
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('Centroid is not initialised for some reason.');
END IF;
end loop;
return v_rc_ref_cursor;
END;
As far as I know, you cannot build up a cursor. Cursors are created and maintained by the database with connections to their source data, transaction and session context, and the like.
I would suggest you declare a type, instantiate it, build up the values in the type.
When you are done, create a cursor by selecting * from table (cast (variable as your_type)).
Munge the cursor into a ref_cursor and return that.
Pro tip is to remember you have data in your table and you can use it for logic. Turns out if I use the IDENTIFIER or ROWID of the row/s which i want then i can do a where clause into a ref cursor that looks up by IDENTIFIER or ROWID.
eg.
open v_rc_ref_cursor for select * from PARCEL_TABLE n where n.identifier = query_row.identifier;
super simple stuff :)

Resources