I try to do the following :
CREATE OR REPLACE PACKAGE my_package AS
-- Declare the global variable
my_variable VARCHAR(255);
END my_package;
/
CREATE OR REPLACE PACKAGE BODY my_package AS
-- Assign a value to the global variable
my_variable := 'test';
END my_package;
/
But this does highlight := and throw the following error :
LINE/COL ERROR
--------- -------------------------------------------------------------
3/15 PLS-00103: Encountered the symbol "=" when expecting one of the following: constant exception <an identifier> <a double-quoted delimited-identifier> table columns long double ref char time timestamp interval date binary national character nchar The symbol "<an identifier>" was substituted for "=" to continue.
Errors: check compiler log
How can I create a package with in it a global variable so I can use it as follow :
my_package.my_variable
If you want to use it in SQL then create a function to wrap the variable:
CREATE OR REPLACE PACKAGE my_package AS
FUNCTION get_my_variable
RETURN VARCHAR2;
END my_package;
/
CREATE OR REPLACE PACKAGE BODY my_package AS
-- Declare the package variable
-- It can be public, if declared in the package specification
-- Or private, if declared in the package body
my_variable VARCHAR(255);
FUNCTION get_my_variable
RETURN VARCHAR2
IS
BEGIN
RETURN my_variable;
END;
BEGIN
-- Assign a value to the global variable
my_variable := 'test';
END my_package;
/
Then you can use it in SQL:
SELECT my_package.get_my_variable() FROM DUAL;
Outputs:
MY_PACKAGE.GET_MY_VARIABLE()
test
fiddle
You are missing a BEGIN block:
CREATE OR REPLACE PACKAGE BODY my_package AS
BEGIN
-- Assign a value to the global variable
my_variable := 10;
END my_package;
/
Related
This is the code:
CREATE PROCEDURE print_string(IN input_string VARCHAR(255))
BEGIN
DECLARE num_chars INT DEFAULT 0;
IF input_string IS NULL THEN
SET num_chars = 0;
ELSE
SET num_chars = CHAR_LENGTH(input_string);
END IF;
SELECT UPPER(input_string), num_chars;
END;
I get error:
PLS-00103: Encountered the symbol "IN" when expecting one of the following: <an identifier> <a double-quoted delimited-identifier>
current delete exists prior
Errors: check compiler log
How do I fix: current delete exists prior?
The immediate error is that you have the argument name and mode the wrong way around - it should be (input_string IN ... not (IN input_string .... But there are other problems:
Oracle recommends VARCHAR2 over VARCHAR.
arguments just have the data type, not a size (or precision/scale), so it should be (input_string IN VARCHAR2) not (input_string IN VARCHAR2(255).
you are missing the IS/AS keyword.
DECLARE comes before BEGIN in a PL/SQL block; having a nested block here would be valid, but you're missing a BEGIN and END; if you do that, and it isn't necessary so I don't think it's what you meant. And you don't need the DECLARE at all for a procedure, it's implied.
if you want a default value for a PL/SQL variable then assign it, rather than using DEFAULT. (You don't really need to do this here, as you always assign a value later anyway, but I'm sticking with your general approach.)
it's probably better to use native Oracle types, so NUMBER or PLS_INTEGER instead of INT.
assignment of values is with :=, not SET ... = ....
CHAR_LENGTH should just be LENGTH (unless you have your own function with that name).
in PL/SQL you have to select into something, and from something. But if you do that here, you still have to return it to the caller somehow.
given that you want to 'print' the string, you probably want dbms_output - though that relies on the client showing the result, which most don't by default, and it's generally only used for debugging...
So this would work:
CREATE PROCEDURE print_string(input_string IN VARCHAR2) AS
num_chars PLS_INTEGER := 0;
BEGIN
IF input_string IS NULL THEN
num_chars := 0;
ELSE
num_chars := LENGTH(input_string);
END IF;
DBMS_OUTPUT.PUT_LINE(UPPER(input_string) || ': ' || num_chars);
END;
/
BEGIN
DBMS_OUTPUT.ENABLE;
print_string('This is a test');
END;
/
1 rows affected
dbms_output:
THIS IS A TEST: 14
fiddle
But again, dbms_output isn't ideal. And it could be done much more simply (#Mto has shown one way), or without using PL/SQL at all.
You can fix the issues (listing in #Alex Poole's answer) and simplify the procedure to:
CREATE PROCEDURE print_string(
input_string IN VARCHAR2
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(UPPER(input_string) || ', ' || COALESCE(LENGTH(input_string), 0));
END;
/
Then:
BEGIN
DBMS_OUTPUT.ENABLE;
print_string('This is a test');
print_string(NULL);
END;
/
Outputs:
THIS IS A TEST, 14
, 0
fiddle
The code syntax is incorrect here. It should be something like
CREATE OR REPLACE PROCEDURE print_string(input_string IN VARCHAR2)
IS
BEGIN
I want to declare amount parameter as type NUMBER(9,2); How come this Oracle PL/SQL procedure doesn't work?
CREATE OR REPLACE PROCEDURE spupdate_price_by_cat(amount IN NUMBER(9, 2))AS
BEGIN
END;
/
When I run it, i get error:
Encountered the symbol "(" when expecting one of the following: := . ) , # % default character. The symbol ":=" was substituted for "(" to continue.
You cannot declare a NUMBER data type with scale and precision in the signature of a PL/SQL function or procedure.
Either use NUMBER:
CREATE OR REPLACE PROCEDURE spupdate_price_by_cat(
amount IN NUMBER
)
AS
BEGIN
NULL;
END;
/
Or use a %TYPE declaration to declare it to have the same data type as a column of a table (but it still does not respect the column's scale and precision in the signature):
CREATE OR REPLACE PROCEDURE spupdate_price_by_cat(
amount IN table_name.column_name%TYPE
)
AS
BEGIN
NULL;
END;
/
If you want a particular scale and precision enforcing in a PL/SQL variable then declare it locally in the procedure:
CREATE OR REPLACE PROCEDURE spupdate_price_by_cat(
amount IN table_name.column_name%TYPE
)
AS
v_amount1 NUMBER(9,2) := amount;
v_amount2 table_name.column_name%TYPE := amount;
BEGIN
DBMS_OUTPUT.PUT_LINE(v_amount1);
END;
/
db<>fiddle here
I tried executing a simple package with function overloading. Below is the package code.
--package specification:
create or replace package over_load as
FUNCTION print_it(v_date date) return date;
FUNCTION print_it(v_name varchar2) return number;
end over_load;
--package body:
create or replace package body over_load as
FUNCTION print_it(v_date date) return date is --function accepting and returning date
begin
dbms_output.put_line('the date is ' || v_date);
return v_date;
end print_it;
FUNCTION print_it(v_name varchar2) return number is /*function accepting string and returning number*/
v_eno employees.employee_id%type;
begin
select employee_id into v_eno from employees where first_name = v_name;
return v_eno;
end print_it;
end over_load;
I tried executing the first function in the package using the below anonymous block.
declare
sample_date date;
begin
sample_date := over_load.print_it('14-07-2017');
dbms_output.put_line(sample_date);
end;
I tried passing date as the argument to the first function, but it throws the wrong argument type error. Any idea on why?
If the procedure (or a function) expects DATE datatype, then don't pass string to it. Because, '14-07-2017' is a string.
SQL> set serveroutput on
SQL>
SQL> declare
2 sample_date date;
3 begin
4 --sample_date := over_load.print_it('14-07-2017');
5 sample_date := over_load.print_it(date '2017-07-14');
6 dbms_output.put_line(sample_date);
7 end;
8 /
the date is 14.07.17
14.07.17
PL/SQL procedure successfully completed.
SQL>
In line #5, I passed a date literal. It could have also been to_date('14-07-2017', 'dd-mm-yyyy').
Oracle - if it can - implicitly converts what you pass to datatype it expects, but it doesn't always succeed; that depends on NLS settings.
To be sure that it'll ALWAYS work, take control over it and use appropriate datatypes.
I have a question and I am not finding the answer from google.
This may be a simple question since I'm a beginner I have this doubt.
Can we declare a function in Package specification and use the same function for forward declaration ?
CREATE OR REPLACE PACKAGE pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER;
PROCEDURE proc_test (id number);
END pckg_test ;
CREATE OR REPLACE PACKAGE BODY pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER; --fwd declaration
PROCEDURE proc_test (id number) is
BEGIN
....
calling fun_test
....
END;
FUNCTION fun_test(ID NUMBER) RETURN NUMBER is
BEGIN
....
END;
END pckg_test;
You can't (forward) declare the function in the body, because it has already been declared in the specification.
This is simple to test with very minor filling-out of your pseudocode:
CREATE OR REPLACE PACKAGE pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER;
PROCEDURE proc_test (id number);
END pckg_test ;
/
Package PCKG_TEST compiled
CREATE OR REPLACE PACKAGE BODY pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER; --fwd declaration
PROCEDURE proc_test (id number) is
x number;
BEGIN
x := fun_test(1);
END;
FUNCTION fun_test(ID NUMBER) RETURN NUMBER is
BEGIN
return 42;
END;
END pckg_test;
/
Package Body PCKG_TEST compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
2/1 PLS-00305: previous use of 'FUN_TEST' (at line 2) conflicts with this use
2/1 PL/SQL: Item ignored
2/10 PLS-00328: A subprogram body must be defined for the forward declaration of FUN_TEST.
Errors: check compiler log
The PLS-00305 is because of your forward declaration, which is the same (name and data types) as that in the package specification.
The PLS-00328 is slightly misleading; the full declaration of fun_test seems to be being linked to the public specification, and the forward declaration - even though it is itself throwing an error - then has no matching full declaration.
If you just remove or comment out the forward declaration then it compiles successfully:
CREATE OR REPLACE PACKAGE BODY pckg_test IS
--FUNCTION fun_test(ID NUMBER) RETURN NUMBER; --fwd declaration
PROCEDURE proc_test (id number) is
x number;
BEGIN
x := fun_test(1);
END;
FUNCTION fun_test(ID NUMBER) RETURN NUMBER is
BEGIN
return 42;
END;
END pckg_test;
/
Package Body PCKG_TEST compiled
You don't need (and are not alowed) a forward declaration of fun_test within the package body because it is publicly declared in the package specification - that public spec makes the function available throughout the package body. So, proc_test can still call fun_test even though it comes first in the body code. The public specification has the same effect as a forward declaration would.
so it means i can give fwd declaration only for private subprograms ?
Yes.
Hey guys I am having an issue where I get an error when I try to add the second private header underneath my first private header.
CREATE OR REPLACE PACKAGE TEST IS
PROCEDURE TEST2(VARIABLE1 IN NUMBER, VARIABLE2 OUT NUMBER);
END;
CREATE OR REPLACE PACK BODY TEST IS
FUNCTION PRIVATE1 (VARIABLE1 IN NUMBER)
RETURN NUMBER;
FUNCTION PRIVATE2 (VARIABLE2 IN NUMBER)
RETURN NUMBER;
PROCEDURE TEST2(VARIABLE IN NUMBER, VARIABLE OUT NUMBER)
BEGIN
......
END;
FUNCTION PRIVATE1 (VARIABLE1 IN NUMBER)
RETURN NUMBER
IS
BEGIN
........
END;
FUNCTION PRIVATE2 (VARIABLE2 IN NUMBER)
RETURN NUMBER
IS
BEGIN
.......
END;
END;
Any suggestions on how I can fix it?
FUNCTION PRIVATE2 (VARIABLE2 IN NUMBER)
RETURN NUMBER; // REMOVE semi colon from here
IS
BEGIN
.......
END;
You are probably using private function in SQL - this is not supported. In order to use function in SQL you have to define it in the package specification.
We need source code of private1 and private2 functions in order to be able to help more.
[Edit] Here is the example of the package that will fail to compile due to using private function in SQL:
create or replace package test_pkg is
end;
/
create or replace package body test_pkg is
function F1 return number is
begin
return 2;
end;
function F2 return number is
lnNumber number;
begin
select F1 -- function declared only in the package body
into lnNumber
from dual;
return lnNumber + 1;
end;
end;
/
PLS-00231: function 'F1' may not be used in SQL
PL/SQL: ORA-00904: "F1": invalid identifier
PL/SQL: SQL Statement ignored