The procedure that makes 1 SELECT(Output data types in the user package). Outside of the SELECT procedure, it works fine. Here is the code:
СREATE OR REPLACE PROCEDURE get_types
IS
BEGIN
select name, type
from user_identifiers
where object_name = 'MY_TYPES'
and usage = 'DECLARATION'
and type != 'PACKAGE'
order by name;
END get_types;
/
Error:
SP2-0734: unknown command beginning "СREATE OR ..." - rest of line ignored.
SQL> SP2-0042: unknown command "IS" - rest of line ignored.
There's something strange with create (as if contains some garbage). I deleted it and typed that word, and code looks OK. However, as it is a PL/SQL procedure, select requires into, such as:
CREATE OR REPLACE PROCEDURE get_types
IS
l_name user_identifiers.name%TYPE;
l_type user_identifiers.TYPE%TYPE;
BEGIN
SELECT name, TYPE
INTO l_name, l_type
FROM user_identifiers
WHERE object_name = 'MY_TYPES'
AND usage = 'DECLARATION'
AND TYPE != 'PACKAGE'
ORDER BY name;
END get_types;
This would work if select returned exactly one row. Otherwise, if it does not, that code will return no_data_found. If it returned more than a single row, you'd get too_many_rows. What to do? It depends on what you want to do. You could select into a collection. Or a refcursor. Or use a loop. There are various options, but actual one depends on you.
Related
I tried to right a procedure to return a table.
that procedure should return a list with an employee info when emp_num parameter equal SSN otherwise return list with all employees info.
First I create a record as below:
CREATE OR REPLACE TYPE emp_record IS OBJECT(emp_lname VARCHAR2(30),
emp_ssn CHAR(9),
emp_sal NUMBER(6));
Then I create table of type emp_record as below:
CREATE OR REPLACE TYPE emp_table IS TABLE OF emp_record;
Then I create a procedure get_employee with two parameters:
CREATE OR REPLACE PROCEDURE get_employee(emp_num IN NUMBER , output_emp OUT emp_table) AS
CURSOR emp_cur IS
SELECT LNAME,SSN,SALARY
FROM EMPLOYEE
WHERE NVL((emp_num = SSN),(SSN = SSN));
BEGIN
IF NOT (emp_cur%ISOPEN) THEN
OPEN emp_cur;
END IF;
LOOP
FETCH emp_cur BULK COLLECT INTO output_emp;
EXIT WHEN output_emp.count=0;
CLOSE emp_cur;
END LOOP;
END;
And when I run that code the below error has appear:
[Warning] ORA-24344: success with compilation error
6/20 PL/SQL: ORA-00907: missing right parenthesis
4/1 PL/SQL: SQL Statement ignored
(1: 0): Warning: compiled but with compilation errors
You have used the alien code here, There is a syntax error:
WHERE
NVL(
(EMP_NUM = SSN),
(SSN = SSN)
);
NVL can take two columns/constants as an input parameter, not a boolean.
You want a WHERE condition - either EMP_NUM is full or if it is not null then it is equal to SSN then You need to use something like this:
WHERE
NVL(EMP_NUM,SSN) = SSN;
or better to use OR condition as follows:
WHERE EMP_NUM IS NULL OR EMP_NUM = SSN;
Please refer Oracle Documentation for NVL syntax. Based on similarity of syntax I feel you probably want to use DECODE instead. If so CASE is the way to go.
Need help
How do I check for a package if it exists or not and skip the creation if it already exists.
I have done the following and I got an error
DECLARE
l_cnt INTEGER;
own VARCHAR(200);
BEGIN
SELECT sys_context( 'userenv', 'current_schema' ) INTO own FROM dual;
SELECT count(*)
INTO l_cnt
FROM ALL_OBJECTS
WHERE object_type = 'PACKAGE'
and object_name = 'JUSTICE_LEAGUE'
AND OWNER = own;
IF( l_cnt <= 0) THEN
EXECUTE IMMEDIATE
'create or replace PACKAGE "JUSTICE_LEAGUE" AS
FUNCTION BATMAN(argPSN INT)
RETURN INT;
FUNCTION SUPERMAN(argSN int)
RETURN Info.infovalue%Type;
PROCEDURE AQUAMAN(argASN INT,argAssignedUser folderProcess.assignedUser%Type DEFAULT 'None');
END JUSTICE_LEAGUE';
DBMS_OUTPUT.PUT_LINE('Package created successfully');
ELSE
DBMS_OUTPUT.PUT_LINE('Package exists already');
END IF;
END;
/
Error report -
ORA-06550: line 23, column 70:
PLS-00103: Encountered the symbol "ALL" when expecting one of the following:
Is it a right way to put the create command for package within EXECUTE IMMEDIATE ?
First of all - no, it is wrong way to do that. The fact that dynamic SQL exists doesn't mean that you should use it, especially not for creating packages (or any other objects). There are really rare situations you'd want to do that.
PL/SQL procedures (functions, packages, triggers) offer create OR REPLACE option so - it is safe to run that statement as is (not as dynamic SQL). It means that:
if it doesn't exist, it'll be created
if it exists, it'll be overwritten by code you've just ran
If you insist on dynamic SQL, check its (package's) existence by querying user_objects:
SQL> select count(*)
2 from user_objects
3 where object_name = 'JUSTICE_LEAGUE'
4 and object_type = 'PACKAGE';
COUNT(*)
----------
0
SQL>
Depending on result, run execute immediate (or not).
There is only one issue with your code.
You have not handled the dynamic query properly. single-quote in the dynamic query must be escaped.
Two single quotes('') in the string are considered as one single quote(') in the final string.
Or you can use the quoted-string (q'{<your_string>}')
replace -- DEFAULT 'None'); with DEFAULT ''None'');
I have a simple test function where I'm passing in a specific ID (the primary key of the table I'm selecting from), and computing a simple function on it and the parameters.
The skeleton code and test:
create or replace function test(id varchar2, area float) return float is
theRow forest%ROWTYPE;
begin
select * into theRow from forest where Forest_No = id;
return area / theRow.Area;
end;
begin
select test('1', 16000) from dual;
end;
The output:
[2019-10-14 21:19:10] [65000][6550] ORA-06550: line 2, column 5:
[2019-10-14 21:19:10] PLS-00428: an INTO clause is expected in this SELECT statement
I am at a loss for what to do here, as far as I can tell the documentation and examples use the same order and syntax. I have tried moving the into clause to the end as in Postgresql, but that did not work.
What have I missed here?
Issue is in calling statement.
Whenever select statement is used in plsql block it must have into clause to assign return value to variable.
You should remove begin and end from your calling code:
--begin -- remove this
select test('1', 16000) from dual;
--end; -- remove this
Or if you want to use it in plsql block then add into clause:
Declare
Area_ float(precision);
begin
select test('1', 16000) into area_ from dual;
-- use area_ in your code wherever required
dbms_output.put_line('area: ' || area_);
end;
Cheers!!
If I run this static SQL in ORACLE SQL DEVELOPER:
SELECT appl_id
FROM grant_appls where full_appl_num IN(
'1R01HL129077-01','2R01HL075494-10A1','2P01HL062426-16') AND SUBPROJECT_ID is not null;
I get these results:
APPL_ID
8855105
8855112
8855104
8855108
8855109
8855107
8855106
Now I write the PROCUDERE and put the Static SQL in there:
create or replace PROCEDURE GET_APPLIDS_BY_FULL_GRANT_NUM (
fullGrantNumList IN VARCHAR2,
applIdRecordSet OUT SYS_REFCURSOR)
AS
BEGIN
OPEN applIdRecordSet FOR
SELECT appl_id
FROM grant_appls where full_appl_num IN
(
'1R01HL129077-01','2R01HL075494-10A1','2P01HL062426-16'
) AND SUBPROJECT_ID is not null;
END GET_APPLIDS_BY_FULL_GRANT_NUM;
I could have sworn at one point I was getting results since I have the static comma delimeted list.
But now I can't even get results with this.
The Ouput Variables window has the variable APPLIDRECORDSET but there are no values for APPL_ID.
The final version should look something like this:
create or replace PROCEDURE GET_APPLIDS_BY_FULL_GRANT_NUM (
fullGrantNumList IN VARCHAR2,
applIdRecordSet OUT SYS_REFCURSOR)
AS
BEGIN
OPEN applIdRecordSet FOR
SELECT appl_id
FROM grant_appls where full_appl_num IN
(
fullGrantNumList
) AND SUBPROJECT_ID is not null;
END GET_APPLIDS_BY_FULL_GRANT_NUM;
So of course when I run this I am getting back null:
VARIABLE cur REFCURSOR
EXECUTE GET_APPLIDS_BY_FULL_GRANT_NUM("'1R01HL129077-01','2R01HL075494- 10A1','2P01HL062426-16'",:cur);
SELECT :cur FROM dual;
Your parameter fullGrantNumList won't be used by Oracle the way you think. Oracle takes the bind variables and treats it as one value, it doesn't do a text replace like you think. Here is what is actually happening to your query:
select appl_id from grant_appls where full_appl_num in ('''1R01HL129077-01'',''2R01HL075494- 10A1'',''2P01HL062426-16''') amd subproject_id is null;
This is actually one of the nice things about bind variables is that they protect you from SQL Injection attacks.
My recommendation would be to either pass in a list of values as a table type or convert the statement to a string and use dynamic SQL to execute it.
Dynamic SQL
The following procedure is not being created in Oracle SQL Developer
CREATE OR REPLACE PROCEDURE CheckUser(UserName IN VARCHAR2,Password IN VARCHAR2)
AS
DECLARE Counts int;
BEGIN
SELECT COUNT(UserNames) INTO Counts FROM tblUsers
WHERE UserNames = UserName and Passwords = Password;
IF Counts = 1 THEN
SELECT 1 AS Code;
ELSE
SELECT -1 AS Code;
END;
When I run above procedure the following error message is returned in SQL Developer:
PROCEDURE CHECKUSER compiled
Errors: check compiler log
Error(3,1): PLS-00103: Encountered the symbol "DECLARE" when expecting
one of the following: begin function pragma procedure subtype type
current
cursor delete exists prior external language
To actually go over your errors:
The procedure declaration CREATE OR REPLACE... is the DECLARE block; you can remove the DECLARE; see the documentation for more information.
You need to select from something, this is normally the table DUAL, which has been designed for this purpose, i.e.
select 1 as code from dual
If you're selecting data in a procedure you need to SELECT INTO a variable. You do this the first time but not the second, i.e.
select 1 into <some variable> from dual
INT is not a datatype; it's INTEGER, which is a synonym for NUMBER(38,0
As far as I can tell you're not actually using the return code at all... I assume you're authenticating users here, which means you need to tell the calling program whether it was successful or not.
If you want to return a value the you probably want a function, as opposed to a procedure.
To take this to it's logical conclusion, your IF statement is unnecessary; the COUNT(*) will return 1 or 0 depending on whether the username and password exist... use this as a Boolean True/False instead.
I hope this is a password hash and not the actual password...
It's often better to be explicit about naming conventions and separate out parameters from column names etc to make it easier to read and less likely to cause Oracle to choke on the scope.
Putting all this together you end up with something like this:
create or replace function check_user (
PUsername in varchar2, PPassword_Hash in varchar2
) return number is
l_exists number;
begin
select count(*) into l_exists
from tblUsers
where username = PUsername
and password = PPassword_Hash
;
return l_exists;
end;
/
It's worth noting that your method of authentication is only safe if you ensure that people can only have one username, i.e. if TBLUSERS has a unique constraint on the column USERNAME. If it doesn't you do need some other method of uniquely identifying each user in your database, otherwise you could end up logging in people as a different user than they actually are.