SQLDeveloper : Not enough arguments - oracle

I'm writing an APEX application which utilises spatial for proximity searching via Googlemaps API, I've built the function and it compiles fine, however whenever I try to run it in SQLDeveloper I get the error not enough arguments.
The function I created to set the new lat/long point takes one input of postcode from my stores table, it then uses the Google map API to return the long lat co-ords for that postcode, which on return builds an SDO_GEOMETRY object, which is returned and set in a location column in the stores table.
Function code:
CREATE OR REPLACE FUNCTION set_spatial_point
(
-- Only accept postcodes from the store table
p_postcode stores.postcode%TYPE
)
RETURN MDSYS.SDO_GEOMETRY
IS
-- Build local variables
l_lng VARCHAR2(100);
l_lat VARCHAR2(100);
n_spatial_object MDSYS.SDO_GEOMETRY;
BEGIN
-- Populate long and lat parameters
POSTCODE_TO_LAT_LNG_GM_API(p_postcode, l_lat, l_lng);
-- Populate the new spatial object
n_spatial_object := MDSYS.SDO_GEOMETRY
(
-- use 01 as we wish to add the point to the map
2001,
-- SRID for WGS84 longitutde/latitude format
8307,
-- Set the information of the point ( we don't need a Z co-ord )
SDO_POINT_TYPE
(
l_lng,
l_lat,
null
),
null, -- We have no SDO_ELEM_INFO_ARRAY
null -- We have no SDO_ORDINATE_ARRAY
);
-- Return the new spatial object
dbms_output.put_line('sdo_gtype='||n_spatial_object.sdo_gtype);
dbms_output.put_line('first element from sdo_ordinates='||n_spatial_object.sdo_ordinates(1));
RETURN n_spatial_object;
END set_spatial_point;
Why am I getting the not enough arguments error, even when I call it with a valid stores.postcode%TYPE, ( I have tried changing to VARCHAR2 but that doesn't make any difference.)
EDIT:
After creating the function, I run a call to the method:
DECLARE
my_object MDSYS.SDO_GEOMETRY;
BEGIN
my_object := set_spatial_value('MK80PB');
END;
I now get the following error:
Error starting at line : 1 in command -
DECLARE
my_object MDSYS.SDO_GEOMETRY;
BEGIN
my_object := set_spatial_value('MK80PB');
END;
Error report -
ORA-06550: line 4, column 14:
PLS-00201: identifier 'SET_SPATIAL_VALUE' must be declared
ORA-06550: line 4, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:

The error you get is obvious: you create the function as SET_SPATIAL_POINT() but you call SET_SPATIAL_VALUE() and that obviously fails since it does not exist.
Now, let's try this out. I had to replace some of your code since I don't have your declarations of the STORES table or the Google call, so I hard-coded the results from that call:
CREATE OR REPLACE FUNCTION set_spatial_point
(
-- Only accept postcodes from the store table
p_postcode varchar2
)
RETURN SDO_GEOMETRY
IS
-- Build local variables
l_lng VARCHAR2(100);
l_lat VARCHAR2(100);
n_spatial_object SDO_GEOMETRY;
BEGIN
-- Populate long and lat parameters
-- POSTCODE_TO_LAT_LNG_GM_API(p_postcode, l_lat, l_lng);
l_lat:=45.3;
l_lng:= 3.7;
-- Populate the new spatial object
n_spatial_object := SDO_GEOMETRY
(
-- use 01 as we wish to add the point to the map
2001,
-- SRID for WGS84 longitutde/latitude format
8307,
-- Set the information of the point ( we don't need a Z co-ord )
SDO_POINT_TYPE
(
l_lng,
l_lat,
null
),
null, -- We have no SDO_ELEM_INFO_ARRAY
null -- We have no SDO_ORDINATE_ARRAY
);
-- Return the new spatial object
dbms_output.put_line('sdo_gtype='||n_spatial_object.sdo_gtype);
dbms_output.put_line('first element from sdo_ordinates='||n_spatial_object.sdo_ordinates(1));
RETURN n_spatial_object;
END set_spatial_point;
/
show errors
That works fine.
Let's try it out:
SQL> select set_spatial_point('XXXX') from dual;
ERROR at line 1:
ORA-06531: Reference to uninitialized collection
ORA-06512: at "SCOTT.SET_SPATIAL_POINT", line 38
Again, this is obvious. The error is on line 38:
dbms_output.put_line('first element from sdo_ordinates='||n_spatial_object.sdo_ordinates(1));
That fails (obviously again) since n_spatial_object.sdo_ordinates() is null (like you wrote on line 32.
Let's remove those debugging lines and redefine the function. Then let's try it out. It now works as expected:
SQL> select set_spatial_point('XXXX') from dual;
SET_SPATIAL_POINT('XXXX')(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INF
-------------------------------------------------------------------------------
SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(3.7, 45.3, NULL), NULL, NULL)
1 row selected.

Related

Getting an error while creating a PL/SQL function

Question is : Function: Create a Function named 'find_credit_card' which takes card_no as input and returns the holder name of type varchar.
Function name: find_credit_card
Input Parameter: card_no with data type as varchar
Output variable : holder_name with data type as varchar(30)
Hint: Add '/' after the end statement
Refer to the schema.
My code :-
CREATE OR REPLACE FUNCTION find_credit_card(card_no IN VARCHAR2(255))
RETURN VARCHAR
IS
holder_name VARCHAR(255)
BEGIN
SELECT name
INTO holder_name
from credit_card
where card_number = card_no;
RETURN(holder_name);
END;
/
Warning : Function created with compilation errors.
Error(s) you got can be reviewed in SQL*Plus by running show err:
Warning: Function created with compilation errors.
SQL> show err
Errors for FUNCTION FIND_CREDIT_CARD:
LINE/COL ERROR
-------- -----------------------------------------------------------------
1/46 PLS-00103: Encountered the symbol "(" when expecting one of the
following:
:= . ) , # % default character
The symbol ":=" was substituted for "(" to continue.
5/1 PLS-00103: Encountered the symbol "BEGIN" when expecting one of
the following:
:= ; not null default character
SQL>
Alternatively, query user_errors:
select line, position, text
from user_errors
where name = 'FIND_CREDIT_CARD';
Oracle says that there are two errors:
first one means that function's parameter shouldn't have size, so - not card_no in varchar2(255) but only card_no in varchar2
another one means that you forgot to terminate line where local variable was declared (missing semi-colon at the end of that line):
holder_name VARCHAR(255);
However, consider inheriting datatype from column description. If it is ever changed, you wouldn't have to modify your code.
Furthermore, it would be good if you distinguish parameters and local variables from column names. How? Use prefixes, e.g. par_ for parameters, l_ or v_ for local variables.
Also, Oracle recommends us to use varchar2, not varchar.
Finally, that function might look like this:
SQL> CREATE OR REPLACE FUNCTION find_credit_card
2 (par_card_number IN credit_card.card_number%TYPE)
3 RETURN credit_card.name%type
4 IS
5 l_holder_name credit_card.name%TYPE;
6 BEGIN
7 SELECT name
8 INTO l_holder_name
9 FROM credit_card
10 WHERE card_number = par_card_number;
11
12 RETURN l_holder_name;
13 END;
14 /
Function created.
SQL> select find_credit_card('HR123456789') holder from dual;
HOLDER
---------------------------------------------------------------------
Littlefoot
SQL>

ORA-24344: success with compilation error in Oracle Apex when compiling a package

I'm working on my university database project in Oracle Apex and I'm getting the ORA-24344: success with compilation error when trying to compile the body package with the following code:
CREATE OR REPLACE PACKAGE BODY band_price_package AS
-- Function that checks if a band has a manager
FUNCTION agent_present(band_id BAND.Band_id%TYPE)
RETURN BOOLEAN
IS
BEGIN
IF BAND.Agent_firstname IS NULL
AND BAND.Agent_lastname IS NULL
AND BAND.Agent_phone IS NULL
AND BAND.Agent_email IS NULL
THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END agent_present;
-- Procedure that gets the band hire price including agent fee
PROCEDURE get_band_cost(band_id IN BAND.Band_id%TYPE,
band_cost OUT BOOKING.Agreed_band_price%TYPE)
IS
BEGIN
IF agent_present(band_id)
THEN
band_cost := BOOKING.Agreed_band_price * 1.25;
ELSE
band_cost := BOOKING.Agreed_band_price;
END IF;
END get_band_cost;
END band_price_package;
/
The following specification has compiled without any errors:
CREATE OR REPLACE PACKAGE band_price_package AS
-- Function that checks if a band has a manager
FUNCTION agent_present(band_id BAND.Band_id%TYPE)
RETURN BOOLEAN;
-- Procedure that gets the band hire price including agent fee
PROCEDURE get_band_cost(band_id IN BAND.Band_id%TYPE,
band_cost OUT BOOKING.Agreed_band_price%TYPE);
END band_price_package;
/
You cannot access tables directly in PL/SQL; so
IF BAND.Agent_firstname IS NULL
AND BAND.Agent_lastname IS NULL
AND BAND.Agent_phone IS NULL
AND BAND.Agent_email IS NULL
is invalid syntax. You need to use an SQL statement inside the PL/SQL block like this:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE BAND(
band_id INTEGER PRIMARY KEY,
Agent_firstname VARCHAR2(200),
Agent_lastname VARCHAR2(200),
Agent_phone VARCHAR2(20),
Agent_email VARCHAR2(100)
)
/
CREATE TABLE BOOKING(
Agreed_band_price NUMBER(10,2)
)
/
CREATE OR REPLACE PACKAGE band_price_package AS
-- Function that checks if a band has a manager
FUNCTION agent_present(
i_band_id BAND.Band_id%TYPE
)
RETURN BOOLEAN;
-- Procedure that gets the band hire price including agent fee
PROCEDURE get_band_cost(
i_band_id IN BAND.Band_id%TYPE,
o_band_cost OUT BOOKING.Agreed_band_price%TYPE
);
END band_price_package;
/
Then you can do:
CREATE OR REPLACE PACKAGE BODY band_price_package AS
-- Function that checks if a band has a manager
FUNCTION agent_present(
i_band_id BAND.Band_id%TYPE
)
RETURN BOOLEAN
IS
agent_exists NUMBER(1,0);
BEGIN
-- Check if an agent exists in the table.
SELECT 1
INTO agent_exists
FROM band
WHERE band_id = i_band_id
AND ( Agent_firstname IS NOT NULL
OR Agent_lastname IS NOT NULL
OR Agent_phone IS NOT NULL
OR Agent_email IS NOT NULL );
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN FALSE;
END agent_present;
-- Procedure that gets the band hire price including agent fee
PROCEDURE get_band_cost(
i_band_id IN BAND.Band_id%TYPE,
o_band_cost OUT BOOKING.Agreed_band_price%TYPE
)
IS
BEGIN
-- Not completed; since it is your homework.
NULL;
END get_band_cost;
END band_price_package;
/
Which tool do you use to access database? In SQLPlus, you should run SHOW ERR which would tell you what's wrong with your code. For example:
SQL> create or replace function f_test return boolean is
2 begin
3 return 1 = 2 --> missing semi-colon
4 end;
5 /
Warning: Function created with compilation errors.
SQL> show err
Errors for FUNCTION F_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/1 PLS-00103: Encountered the symbol "END" when expecting one of the
following:
* & - + ; / at mod remainder rem <an exponent (**)> and or ||
multiset
The symbol ";" was substituted for "END" to continue.
SQL>
GUI tools usually have the "Errors" tab in Object Navigator which display the same.
As of your code, a few blind guesses (as we don't have your tables and can't test it ourselves):
function AGENT_PRESENT accepts BAND_ID as a parameter, which is declared as a BAND.BAND_ID column datatype. You can't reference other BAND table columns the way you do - you should SELECT those columns into variables (or, if you want, declare a rowtype variable and work with it) and then detect whether they are present or not.
procedure GET_BAND_COST calls BOOKING.AGREED_BAND_PRICE which is unknown (at least, it is not declared in that package). So, what is it? Is it a table column? If so, you can't modify it that way - use UPDATE instead.

How do I display a nested table in Oracle - PL/SQL?

I have an assignment where I'm supposed to create a user-defined function that will return all employees after 1968. My code is as follows:
First I create a new object, called emp_dobs, to hold the employees' firstname, lastname, and date of birth, using the same data types as the original employee table:
CREATE OR REPLACE TYPE emp_dobs AS OBJECT (
emp_fname VARCHAR2(20),
emp_lname VARCHAR2(20),
emp_dob DATE
);
/
Then I create emp_dobs_nested as a table of emp_dobs:
CREATE OR REPLACE TYPE emp_dobs_nested AS TABLE OF emp_dobs;
/
Lastly, I create a function that's supposed to return an emp_dobs_nested table:
CREATE OR REPLACE FUNCTION get_emp_dobs RETURN emp_dobs_nested
AS
dobs emp_dobs_nested;
BEGIN
SELECT emp_dobs(firstname, lastname, birthdate) BULK COLLECT INTO dobs
FROM employee
WHERE birthdate < TO_DATE('01-JAN-1968', 'DD-MON-YYYY');
RETURN dobs;
END;
/
There is a weird quirk with compiling emp_dob_nested, however, where Oracle SQL Developer will display a new tab labeled "Output Variables - Log," and only show EMP_FNAME and EMP_LNAME. Despite that, everything compiles.
Now I want to test the function and display its results to prove that it works, but when I try this:
DECLARE
dobs emp_dobs_nested;
BEGIN
dobs := get_emp_dobs;
DBMS_OUTPUT.PUT_LINE(dobs);
END;
/
I get this error:
Error report -
ORA-06550: line 5, column 5:
PLS-00306: wrong number or types of arguments in call to 'PUT_LINE'
ORA-06550: line 5, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
What am I missing here? Thanks.
You cannot pass the whole collection to DBMS_OUTPUT, rather you must loop through it and display individual columns at each index.
DECLARE
dobs emp_dobs_nested;
BEGIN
dobs := get_emp_dobs;
FOR i IN 1..dobs.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(dobs(i).emp_fname||','||dobs(i).emp_lname||','||dobs(i).emp_dob);
END LOOP;
END;
/
You can also use TABLE function to unnest a collection of objects into a relational resultset:
select * from table( get_emp_dobs )
Live demo: http://sqlfiddle.com/#!4/8cfb2/1
Another way of display is to use XML, try
DBMS_OUTPUT.PUT_LINE(XMLTYPE(dobs));
why not a create a view instead?
CREATE VIEW emp_view
AS
SELECT firstname, lastname, birthdate
FROM employee
WHERE birthdate < TO_DATE('01-JAN-1968', 'DD-MON-YYYY');
You can also try this,
DECLARE
dobs emp_dobs_nested;
i NUMBER := 0;
BEGIN
dobs := get_emp_dobs;
LOOP
i := dobs.NEXT(i);
DBMS_OUTPUT.PUT_LINE(dobs(i).emp_fname||','||dobs(i).emp_lname||','||dobs(i).emp_dob);
IF i = dobs.LAST THEN
EXIT;
END IF;
END LOOP;
END;
/

Error calling stored procedure from PHP

I have a problem with this code in Oracle:
create or replace procedure InsertarEntertNotica (IDSUBTOPIC out varchar,
TEXT out varchar,IMAGE out varchar,STADE out varchar,TITT out varchar)
is
idS varchar2(3) := IDSUBTOPIC;
txt varchar2(4000) := TEXT;
img varchar2(100) := IMAGE;
st varchar2(2) := STADE;
fech varchar2(30);
tit varchar2(300) := TITT;
hor date;
begin
SELECT TO_CHAR(SYSDATE,'DD/MM/YY') into fech FROM DUAL;
SELECT SYSDATE into hor FROM DUAL;
insert into ENTERTAIMENT (IDSUBTEMA,TEXTO,IMAGEN,ESTADO,FECHA,TITULO,HORA)
values (idS,txt,img,st,fech,tit,hor);
end;
When I create this SP, I have not problem, but when I execute it I have this problem
Error starting at line : 377 in command -
execute InsertarEntertNotica('ET','Texto de la Noticia Proc','','No','Noticia con Procedimiento')
Error report -
ORA-06550: line 1, column 28:
PLS-00363: expression 'ET' cannot be used as an assignment target
ORA-06550: line 1, column 33:
PLS-00363: expression 'Texto de la Noticia Proc' cannot be used as an assignment target
ORA-06550: line 1, column 60:
PLS-00363: expression '<null>' cannot be used as an assignment target
ORA-06550: line 1, column 63:
PLS-00363: expression 'No' cannot be used as an assignment target
ORA-06550: line 1, column 68:
PLS-00363: expression 'Noticia con Procedimiento' cannot be used as an assignment target
ORA-06550: line 1, column 7:
You've declared all your formal parameters as OUT, which means when you call the procedure you must pass updatable variables, not fixed string values. The documentation shows how IN/OUT works.
You can just change them to IN. You also don't need any of the local variables:
create or replace procedure InsertarEntertNotica (IDSUBTOPIC in varchar,
TEXT in varchar,IMAGE in varchar,STADE in varchar,TITT in varchar)
is
begin
insert into ENTERTAIMENT (IDSUBTEMA, TEXTO, IMAGEN, ESTADO, FECHA, TITULO, HORA)
values (IDSUBTOPIC, TEXT, IMAGE, STADE, TO_CHAR(SYSDATE,'DD/MM/YY'),
TITT, SYSDATE);
end;
If you are going to have local variables then names that distinguish from the parameter names would be good. It's common to use a prefix to distinguish, e.g. p_text for the parameter and l_text for the local variable.
Using TO_CHAR(SYSDATE,'DD/MM/YY') looks wrong for a couple of reasons. Two digit years can cause unexpected results, as well as the infamous Y2K problems. If FECHA is a DATE column rather than VARCHAR2(8), as it should be, then you are implicitly converting that string back to a date using the session NLS settings - which is dangerous, and will only work at all if the session happens to also be DD/MM/YY. If you're really trying to store today's date with the time as midnight then you should use TRUNC(SYSDATE) instead. Although not sure why you'd store that as a separate column to HORA anyway.

SQLPLUS object system. is invalid

I'm stuck with some simple procedure and I can't figure out why.
This is my code, which I'm running in sqlplus:
CREATE OR REPLACE PROCEDURE NormalizeName(fullname IN NVARCHAR2)
IS
BEGIN
SELECT TRIM(fullname) INTO fullname FROM DUAL;
DBMS_OUTPUT.PUT_LINE(fullname);
END NormalizeName;
/
BEGIN
NormalizeName('Alice Wonderland ');
END;
/
When I run it, I get the error:
Warning: Procedure created with compilation errors.
NormalizeName('Alice Wonderland ');
*
ERROR at line 2:
ORA-06550: line 2, column 2:
PLS-00905: object SYSTEM.NORMALIZENAME is invalid
ORA-06550: line 2, column 2:
PL/SQL: Statement ignored
What's wrong?
1) Never create objects in the SYS or SYSTEM schema. Those are reserved for Oracle. If you want to create objects, create a new schema first.
2) When you see that a procedure has been created with compilation errors in SQL*Plus, type show errors to see the errors.
3) The error appears to be that your SELECT statement is trying to write to the fullname parameter. But that parameter is defined as an IN parameter, not IN OUT, so it is read-only. If you define the parameter as IN OUT, though, you could not pass a string constant to the procedure, you'd need to define a local variable in your calling block. It doesn't make a lot of sense to have a procedure that doesn't do anything other than call dbms_output since there is no guarantee that anyone will see the data written to that buffer. My guess is that you really want a function that returns a normalized name. Something like
CREATE OR REPLACE FUNCTION NormalizeName( p_full_name IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN TRIM( p_full_name );
END;
which you can then call
DECLARE
l_normalized_name VARCHAR2(100);
BEGIN
l_normalized_name := NormalizeName( 'Alice Wonderland ' );
dbms_output.put_line( l_normalized_name );
END;
If you really need a procedure because this is a homework assignment
CREATE OR REPLACE PROCEDURE NormalizeName( p_fullname IN VARCHAR2 )
AS
BEGIN
dbms_output.put_line( TRIM( p_fullname ));
END;
In the real world, you should only be using procedures when you want to manipulate the state of the database (i.e. you're doing INSERT, UPDATE, DELETE, MERGE, etc.). You use functions when you want to perform calculations without changing the state of the database or when you want to manipulate data passed in parameters.

Resources