Oracle procedure with default and to_date shows error - oracle

I am using 11g
I have table
CREATE TABLE Agency
(
AgencyID int not null PRIMARY KEY,
AgencyName VARCHAR2(30) not null,
AgencyLtrCode VARCHAR2(10) not null,
IsActive VARCHAR2(3) DEFAULT 'yes'NOT NULL,
LastListSentData DATE DEFAULT SYSDATE ,
LetterSendDate DATE DEFAULT SYSDATE ,
CertificationDate DATE DEFAULT SYSDATE ,
CeresNo int,
AgencyAreaID int not null,
CONSTRAINT fk_Agency FOREIGN KEY (AgencyAreaID) REFERENCES AgencyArea(AriaID)
);
I use procedure to insert new records in it
create or replace PROCEDURE insert_AGENCY_Procedure(
AGENCYID IN AGENCY.AGENCYID%TYPE,
AGENCYNAME IN AGENCY.AGENCYNAME%TYPE,
AGENCYLTRCODE IN AGENCY.AGENCYLTRCODE%TYPE,
ISACTIVE IN AGENCY.ISACTIVE%TYPE DEFAULT 'yes',
LASTLISTSENTDATA IN AGENCY.LASTLISTSENTDATA%TYPE DEFAULT SYSDATE,
LETTERSENDDATE IN AGENCY.LETTERSENDDATE%TYPE DEFAULT SYSDATE,
CERTIFICATIONDATE IN AGENCY.CERTIFICATIONDATE%TYPE DEFAULT SYSDATE,
CERESNO IN AGENCY.CERESNO%TYPE,
AGENCYAREAID IN AGENCY.AGENCYAREAID%TYPE)
IS BEGIN
INSERT INTO AGENCY("AGENCYID", "AGENCYNAME","AGENCYLTRCODE","ISACTIVE","LASTLISTSENTDATA","LETTERSENDDATE","CERTIFICATIONDATE","CERESNO","AGENCYAREAID")
VALUES (AGENCYID, AGENCYNAME,AGENCYLTRCODE,ISACTIVE,LASTLISTSENTDATA,LETTERSENDDATE,CERTIFICATIONDATE,CERESNO,AGENCYAREAID);
COMMIT;
END;​​
right now it throw error "Error at line 17: PLS-00103: Encountered the symbol "" "
line 17 had only END; on it
when I submit inserting which looks like
BEGIN
insert_AGENCY_Procedure(9003,'Some Other Church', 'SomOTCh','no',10-10-2011,10/10/2011,10/10/2011,17,2 );
END;
it throws error
ORA-06550: line 2, column 4:
PLS-00306: wrong number or types of arguments in call to 'INSERT_AGENCY_PROCEDURE'
ORA-06550: line 2, column 4:
PL/SQL: Statement ignored
or other insert like
BEGIN
insert_AGENCY_Procedure(9003,'Some Other Church',SomOTCh',DEFAULT,DEFAULT,DEFAULT,DEFAULT,17,2 );
END;
it throws error
ORA-06550: line 2, column 64:
PLS-00103: Encountered the symbol "DEFAULT" when expecting one of the following:
( - + case mod new not null
The question is what is wrong with my procedure? I was trying to resolve this problem but stuck :(

First off, the INSERT_AGENCY_PROCEDURE procedure is defined to take 8 parameters but you are trying to pass in 9 parameters. It appears that you are trying to pass in an AgencyLtrCode but the procedure does not take an AgencyLtrCode as a parameter. You would either have to stop trying to pass in the AgencyLtrCode or you would need to modify the procedure to accept that parameter.
Second, you need to pass dates to the procedure given the declaration. Your actual procedure call will error out because what you are passing in for the date parameters are not dates (and cannot be implicitly converted to dates). Assuming that we eliminate the third parameter (which is what appears to be the AgencyLtrCode discussed above), you would want something like
BEGIN
insert_AGENCY_Procedure(9003,
'Some Other Church',
'no',
to_date('10-10-2011', 'DD-MM-YYYY'),
to_date('10/10/2011', 'DD/MM/YYYY'),
to_date('10/10/2011','DD/MM/YYYY'),
17,
2 );
END;
Third, your procedure is incorrect. The parameters LASTLISTSENTDATA, LETTERSENDDATE, and CERTIFICATIONDATE are defined as dates so you should not call to_date on them. If you do, you force Oracle to implicitly convert the date to a string using the session's NLS_DATE_FORMAT, then convert the string back to a date using the explicit format mask. That will fail if the session's NLS_DATE_FORMAT is not what you expect.
Finally, declaring optional parameters in the middle of a procedure declaration is rarely correct. If you want to use positional binding and you want the ability to omit parameters, the optional parameters need to be at the end of the parameter list. You can define optional parameters in the middle of the parameter list and then use named binds (as DazzaL demonstrates) but that is seldom what you want to force future developers to use.
In your updated procedure, the declaration of the AgencyLtrCode parameter appears to be incorrect
AGENCYLTRCODE IN AGENCYLTRCODE%TYPE
needs to be
AGENCYLTRCODE IN AGENCY.AGENCYLTRCODE%TYPE
You are missing the name of the table.

You're passing ninevalues, but the procedure is only expecting eight. From the table definition you seem to be missingAgencyLtrCode in the procedure.
In the first call you're passing dates as 10-10-2011 or 10/10/2011, which will be evaluated as (different) numbers not dates. You need to at least enclose them in single quotes, but really ought to specify the date mask, as to_date('10/10/2011', 'DD/MM/YYYY') rather than relying on implicit conversions.
In general, if you want to use the defaults, just leave those parameters out, do not pass DEFAULT; that isn't valid in that context. But because you have values to pass after the defaults, you need to name the parameters, i.e.
insert_agency_procedure(agency_id=>9003, ...);

there is no DEFAULT keyword, you just omit the defaults.
in your case you have the defaults in the middle of the API though, so you'd have to use NAMED notation:
begin
insert_agency_procedure(agencyid => 9003,
agencyname => 'Some Other Church',
isactive => 'SomOTCh',
ceresno => 17,
agencyareaid => 2 );
end;
/
or mixed:
begin
insert_agency_procedure(9003, 'Some Other Church',
'SomOTCh',
ceresno => 17,
agencyareaid => 2 );
end;
/
and in the first exmaple you gave:
BEGIN
insert_AGENCY_Procedure(9003,'Some Other Church', 'SomOTCh','no',10-10-2011,10/10/2011,10/10/2011,17,2 );
END;
you cant just type dates like that. Firstly quote them. Secondly always always use a format mask.
BEGIN
insert_AGENCY_Procedure(9003,'Some Other Church', 'SomOTCh','no',
to_date('10-10-2011', 'dd-mm-yyyy'),
to_date('10-10-2011', 'dd-mm-yyyy'),
to_date('10-10-2011', 'dd-mm-yyyy'),17,2 );
END;

I think you need to enclose your date string in single quotes (if you supply a date, considering you have default values for those parameters):
BEGIN
insert_AGENCY_Procedure(9003,'Some Other Church', 'SomOTCh','no','10-10-2011','10/10/2011','10/10/2011',17,2 );
END;

Related

Error(13,61): PL/SQL: ORA-00984: column not allowed here IN PROCEDURE WHEN PASS IN PARAMETER

CREATE OR REPLACE PROCEDURE INSEMP
(
EMPNOS IN VARCHAR2
, ENAMES IN VARCHAR2
, JOBAS IN VARCHAR2
, MGRS IN VARCHAR2
, HIREDATES IN VARCHAR2
, SALS IN VARCHAR2
, COMMISSIONS IN VARCHAR2
, DEPTNOS IN VARCHAR2
) AS
BEGIN
INSERT INTO emp VALUES (EMPNOS,ENAMES,JOBAS,MGRS,HIREDATES,SALS,COMMS,DEPTNOS);
END INSEMP;
When I execute the above, I get an error: Error(13,67): PL/SQL: ORA-00984: column not allowed here.
I know when we insert
INSERT INTO EMP VALUES ('DSFD'DSFDFD', ...)
we have to use single quotes, but how do I pass the values in via the parameters?
Your issue is that you have a parameter called COMMISSIONS but in your insert statement, you are passing in a value of COMMS.
Also, make sure your parameters have different names to the columns you're trying to insert into; this is (IMO) good practice across any PL/SQL code you're writing, as you can have unexpected results when name collisions happen.
Change your insert statement to use the right parameter name (or, alternatively, change the name of the parameter to match your insert statement) and it should start working.
One point, though: it is bad practice to not list the columns you are inserting into. In real production code, if someone added a column to the table, your code would break.
Your insert statement would be better written as:
insert into <table> (<list of columns to be inserted into>)
values (<list of values to insert into those columns>);

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.

Can I execute a procedure with default null parameters?

I recently created a procedure that is defined like this:
create or replace
PACKAGE
pkg_dml_legal_transactions
AS
PROCEDURE spm_update_court_cost(
p_court_state IN legal_court_cost.state%TYPE,
p_tran_code IN legal_court_cost.transaction_code%TYPE,
p_legal_court IN legal_court_cost.court%TYPE default null,
p_end_date IN legal_court_cost.end_date%TYPE,
p_cost_min IN legal_court_cost.cost_range_min%TYPE,
p_cost_max IN legal_court_cost.cost_range_max%TYPE,
p_bal_min IN legal_court_cost.bal_range_min%TYPE DEFAULT NULL,
p_bal_max IN legal_court_cost.bal_range_max%TYPE DEFAULT NULL);
end pkg_dml_legal_transactions;
When I attempt to execute the procedure, I get an error stating that:
PLS-00306: wrong number or types of arguments in call to 'SPM_UPDATE_COURT_COST'
Here is what my execute statement looks like:
execute pkg_dml_legal_transactions.spm_update_court_cost('NJ',1,sysdate,1000,40000);
Now I understand what the error means, but I figured if the parameters are defaulted to null then I could just skip them over, but apparently not. Is there a way around this?
In PL/SQL, you can call a procedure using either named parameter notation or positional notation. If you want to skip some parameters, you'll need to use named parameter notation
execute pkg_dml_legal_transactions.spm_update_court_cost( p_court_state => 'NJ',
p_tran_code => 1,
p_end_date => sysdate,
p_cost_min => 1000,
p_cost_max => 40000 );
Generally, when you're designing a procedure, you would put all the optional parameters at the end so that the caller could also use positional notation.
You can use mixed approach, positional notation until first omitted parameter, named notation for the rest.
declare
procedure do_something(p_foo IN NUMBER
,p_bar IN VARCHAR2 DEFAULT NULL
,p_baz IN VARCHAR2) IS
begin
null;
end;
begin
do_something(12, p_baz => 'abc');
end;
But I would choose what Justin proposed.

Oracle dynamic PL/SQL. I cant get it to work

So here is my code:
CREATE OR REPLACE PROCEDURE UPDATE_USER
(
updateColumn IN USERS.column_name%type,
changeStr IN VARCHAR2,
unID IN VARCHAR2
)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE
users
SET :1 = :2
WHERE
uniqueID = :3'
USING updateColumn, changeStr, unID;
END;
/
I've searched for other answers on this and as far as I can tell this should work. However I get the error:
'Error(3,25): PLS-00302: component 'COLUMN_NAME' must be declared'
Thanks.
The error message specifies line 3, character 25, which points to column_name in the declaration of the updateColumn parameter. It appears that you are trying to pass the column name to update as a parameter, but that means that at compile time the column isn't known, so its type can't be known. This also doesn't really make sense - if it's a number column then you'd be trying to pass the column name into a numeric parameter, which wouldn't work anyway. If you don't want to declare it as a simple varchar2, you could instead use user_tab_columns.column_name%type.
But you can't dynamically set the column name in the update statement using a bind variable. It would compile, but would get an ORA-01747 on execution from the apparent name starting with a colon. You'd need to concatenate it, something like:
CREATE OR REPLACE PROCEDURE UPDATE_USER
(
updateColumn IN user_tab_columns.column_name%type,
changeStr IN VARCHAR2,
unID IN VARCHAR2
)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE
users
SET ' || updateColumn || ' = :1
WHERE
uniqueID = :2'
USING changeStr, unID;
END;
/
But you'd need to sanitise the column name to avoid SQL injection. APC's answer to the question you linked to mentions using the DBMS_ASSERT package, for example.

Resources