This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I've got a table called BANKCUSTOMER with the following columns:
USERNAME NOT NULL VARCHAR2(11)
FAMILY_NAME NOT NULL VARCHAR2(25)
NAME NOT NULL VARCHAR2(25)
PASSWD NOT NULL VARCHAR2(6)
I want to make a function which checks in the database if the users USERNAME and PASSWORD matches the data in the database. If the login succeeds then it should print out "Login successful!" otherwise "Wrong username or password!"
I visited a pl/sql tutorial site and came over the following code which i modified a bit so it can work with my database, but there is something I don't understand and that is what z number does and what begin select 1 into z does. Could someone please explain that for me.
create or replace function log_in(x in varchar2, y in varchar2)
return varchar2
as
z number;
begin
select 1
into z
from bankcustomer
where username=x
and passwd=y;
dbms_output.put_line('Login successful!');
exception
when no_data_found then
dbms_output.put_line('Wrong username or password!');
end;
I would like to test the function by writing SELECT log_in() FROM dual; to see if it works. When I write SELECT log_in() FROM dual; I get an error message saying:
Error starting at line 1 in command:
SELECT log_in() FROM dual
Error at Command Line:1 Column:7
Error report:
SQL Error: ORA-06553: PLS-306: wrong number or types of arguments in call to 'LOG_IN'
06553. 00000 - "PLS-%s: %s"
*Cause:
*Action:
How can this be resolved?
You have defined a function but do not return a value from it. Given the fact that you "select" the function there is no need to use dbms_output:
create or replace function log_in(x in varchar2, y in varchar2)
return varchar2
as
match_count number;
begin
select count(*)
into match_count
from bankcustomer
where username=x
and passwd=y;
if match_count = 0 then
return 'Wrong username or password!';
elsif match_count = 1 then
return 'Login successful!';
else
return 'Too many matches, this should never happen!';
end if;
end;
/
Additionally your call to the function does not provide the username and password parameters, that's why you get the error message. Assuming you have changed the function to actually return something, you need to use
SELECT log_in('username', 'secretpassword') FROM dual;
Have you actually passed any arguments to the log_in function? And what is logga_in()? Is the latter a typo on your side?
Anyway, the select 1 into z only forces an exception in case no match is found. Nothing more.
In other words, you could write the code without it, for example with select count(*) into authenticated ... and then you could check if authenticated != 0 and do the appropriate action. I don't have an Oracle instance so this code is written blindly, you'll need to test it:
create or replace function log_in(x in varchar2, y in varchar2)
return varchar2
as
match_count number;
begin
select count(*)
into match_count
from bankcustomer
where username=x
and passwd=y;
if match_count = 0 then
dbms_output.put_line('Wrong username or password!');
elsif match_count = 1 then
dbms_output.put_line('Login successful!');
else
dbms_output.put_line('Too many matches, this should never happen!');
end;
Just to add more information to what's already been provided, the BEGIN keyword indicates the beginning of the execution block; what's above that is the function header and any declaration statements.
The statement z number; is a variable declaration statement declaring a variable that is named z and is of the datatype number. The SELECT 1 INTO z WHERE... statement is checking the BANKCUSTOMER table for a row where the username matches what's passed to the function in the first parameter, and a password that matches what's passed to the function in the second parameter.
If there is a row where the username and password match what's passed to the function, then the variable z will contain the number 1. If there isn't, the Oracle NO_ROWS_FOUND exception will be raised, because SELECT...INTO statements must always select one and only one row, or else they will raise an exception (the NO_ROWS_FOUND exception for no rows, and the TOO_MANY_ROWS exception for more than one row).
Hope that's helpful! Don't hesitate to ask if you have more questions.
Related
I have a problem where my SQL sequence has to be above a certain number to fix a unique constraint error. Now I started to write an if-statement that checks for a certain number and if it's below it should be increased to a certain number. The statement is for Postgres.
I got the separate parts running but the connection over if is throwing an error and I don't know why.
First for selecting the current number:
SELECT nextval('mySequence')
Then to update the number:
SELECT setval('mySequence', targetNumber, true)
The full statement looks something like this in my tries:
IF (SELECT nextval('mySequence') < targetNumber)
THEN (SELECT setval('mySequence', targetNumber, true))
END IF;
and the error is
ERROR: syntax error at »IF«
Can someone explain to me what I did wrong there because the error message isn't giving me much to work with? I would appreciate your help.
Try this:
SELECT setval('mySequence', targetNumber, true)
WHERE (SELECT nextval('mySequence') < targetNumber) is true;
You can use postgres functions if you want to use IF statement.
You can try something like this:
CREATE SEQUENCE seq_test_id_seq;
CREATE TABLE seq_test(
id integer NOT NULL DEFAULT nextval('seq_test_id_seq'),
name VARCHAR
);
CREATE OR REPLACE FUNCTION seq_test_function(target_number bigint)
RETURNS void
LANGUAGE 'plpgsql'
VOLATILE
PARALLEL UNSAFE
COST 100
AS $BODY$
DECLARE
seq_val INTEGER;
BEGIN
SELECT nextval('seq_test_id_seq') INTO seq_val;
RAISE NOTICE 'NEXT SEQUENCE [%]', seq_val;
IF (seq_val < target_number) THEN
SELECT setval('seq_test_id_seq', target_number, true) INTO seq_val;
RAISE NOTICE 'SEQUENCE VALUE MODIFIED [%]', seq_val;
END IF;
END;
$BODY$;
Then call the procedure:
select seq_test_function(10);
i have this questions i am trying to solve and find below what i have solved so far. although the stored procedure haveno error but calling it i get this error :
ERROR at line 2: ORA-06550: line 2, column 3: PLS-00306: wrong
number or types of arguments in call to 'PUB_JOB_COUNT' ORA-06550:
line 2, column 3: PL/SQL: Statement ignored
Requirement:
Create a stored PL/SQL procedure object in the database. The procedure
should insert the publisher’s name, city, telephone number and the
number (count) of jobs he/she requested in the table PublisherDetails
for each Publisher who requested less than three print jobs otherwise
the procedure should display on the screen the publisher name followed
by job number, job start date and job completion date for each job
he/she requested. Screen output (hint: use the concatenation operator
‘||’) should be in the following format:
Please someone help me out please?
Publisher Name: Addison-Wesley
JobNo Start Date Completion Date
12 17-JAN-14 25-JAN-14
14 28-FEB-14 01-APR-14
Finally, a NO-DATA-FOUND exception should be catered for in the
EXCEPTION section and a message displayed on the screen (hint: use
DBMS_OUTPUT.put_line procedure provided by Oracle) informing the user
if such an error arises. Note that in order for DBMS_OUTPUT.put_line
to work in SQL*Plus, you should set SERVEROUTPUT on first. You should
check if the procedure executes properly by invoking the procedure and
checking the content of the PublisherDetails table. Do the following:
a) Create a script file with the necessary code to create the table
PublisherDetails and the PL/SQL procedure in the database; b) Create a
second script file with the following: • An SQL statement that clears
the content of the table PublisherDetails; • A PL/SQL anonymous block
statement to invoke (execute) the PL/SQL procedure; • A SELECT
statement to select all the records in PublisherDetails table.
my tables
publisher(publisherName, publisherCity, phoneNo)
pk
printJob(JobNo, startDate, complitionDate, publisherName)
pk fk(publisher)
publisherdetails(publisherName, publisherCity, phoneNo, JobNo)
pk
Code:
CREATE OR REPLACE PROCEDURE PUB_JOB_COUNT (
JOBNO IN NUMBER
) AS
PUBLISHERNAME PRINTJOB.PUBLISHERNAME%TYPE;
NOTFOUND EXCEPTION;
CURSOR PUBCURSOR IS
SELECT PUBLISHER.PUBLISHERNAME,
PUBLISHER.PUBLISHERCITY,
PUBLISHER.PHONENO,
PRINTJOB.STARTDATE,
PRINTJOB.COMPLETIONDATE,
SUM(JOBNO) AS NUMOFJOBS
FROM PUBLISHER
INNER JOIN PRINTJOB ON PUBLISHER.PUBLISHERNAME = PRINTJOB.PUBLISHERNAME
GROUP BY PUBLISHER.PUBLISHERNAME,
PUBLISHER.PUBLISHERCITY,
PUBLISHER.PHONENO,
PRINTJOB.STARTDATE,
PRINTJOB.COMPLETIONDATE;
PUBREC PUBCURSOR%ROWTYPE;
BEGIN
OPEN PUBCURSOR;
FOR PRINTJOB IN PUBCURSOR LOOP
PUBLISHERNAME := PRINTJOB.PUBLISHERNAME;
DBMS_OUTPUT.PUT_LINE('Publisher Name : ' || PRINTJOB.PUBLISHERNAME);
LOOP
FETCH PUBCURSOR INTO PUBREC;
EXIT WHEN PUBCURSOR%NOTFOUND;
IF PUBREC.NUMOFJOBS <= 3 THEN INSERT INTO PUBLISHERDETAILS VALUES (
PUBREC.PUBLISHERNAME,
PUBREC.PUBLISHERCITY,
PUBREC.PHONENO,
PUBREC.NUMOFJOBS
);
ELSE DBMS_OUTPUT.PUT_LINE(PUBREC.NUMOFJOBS
|| ' '
|| PUBREC.STARTDATE
|| ' '
|| PUBREC.COMPLETIONDATE);
END IF;
END LOOP;
END LOOP;
CLOSE PUBCURSOR;
COMMIT;
EXCEPTION
WHEN NOTFOUND THEN DBMS_OUTPUT.PUT_LINE('Record Not Found');
END;
Gleaned from comments below, the code being used to execute the procedure:
BEGIN
pub_Job_Count;
End;
Your program is expecting an input, a number.
But when you call it, you're not providing said number.
So, the database gets upset and issues this:
PLS-00306: wrong number or types of arguments in call to 'PUB_JOB_COUNT'
To fix it,
BEGIN
pub_Job_Count(1); -- your number is added here, either explicitley or via a variable you add in a DECLARE
END;
/
A basic example
clear screen
create or replace procedure so_missing_inputs (x in integer, y in date) is
begin
dbms_output.put_line('X is: ' || x);
dbms_output.put_line('Y is: ' || to_char(y, 'MM-DD-YYYY HH24:MI:SS'));
end;
/
set serveroutput on
declare
a integer := 2;
b date := sysdate;
begin
-- so_missing_inputs(); -- missing 2 inputes
-- so_missing_inputs(1); -- missing 1 inputs
-- so_missing_inputs(sysdate, 2); -- right number of inputs, but not right data types
so_missing_inputs(x => a, y => b); -- let's be explicit about inputs vs coutning on right order
end;
/
If I run this -
If you were to uncomment one of the previous lines, you'd see the PLS-00306 creep back in.
One final note, on DBMS_OUTPUT. It's a good way to see what things are happening while 'debugging' your code, but it's not a good way to communicate things outside the PL/SQL program.
My table looks like this
Teacher(ID, Name, Surname)
I want to give the user an output.
In case the id given as parameter to the function does not exist in the ID column in the table.
How can I handle this inside a function and give an output:
"The id asked is not present in the table"
Create or replace function subjects
(
code_value IN Teacher.ID % TYPE
)
RETURN NUMBER
IS
id_value NUMBER
BEGIN
SELECT id
INTO id_value
FROM TEACHER
WHERE ID = code_value
END
END subjects;
With a function you wrote, you can not - it returns a NUMBER while the result you want is a string (VARCHAR2).
There is a way - to write an exception handler which will be executed when select you wrote doesn't return anything as it'll raise NO_DATA_FOUND, so:
begin
select ...
exception
when no_data_found then
raise_application_error(-20000, 'The id asked is not present in the table');
end;
This will cause your program to stop (an error is raised, right?) so - if you want to move on, either
change return datatype or
switch to a procedure which will have an OUT parameter (or two - one for the ID, another for possible error message). Its (procedure's) drawback is that you can't use it in SELECT statements but you'll need a piece of PL/SQL code.
I have been tasked (as part of an assignment) to write a stored procedure in Oracle PL/SQL. There are 3 requirements that have to be met.
There must be 2 parameters, 1 IN and 1 OUT.
I must use an implicit cursor and SQL function to calculate a count of the numbers of fields of the same type (in this case the type is car models, so how many cars of each model are there).
I must use another implicit cursor to display the description of the models.
To be honest, I am at a loss. So far for the stored proc I have:
CREATE OR REPLACE Procedure model_details_sp
(p_model IN VARCHAR2,
p_noofcars OUT NUMBER)
IS
BEGIN
SELECT COUNT(Model_Name) INTO p_noofcars
FROM i_car
GROUP BY Model_Name;
END;
I really have no idea where to go from here. Any advice or direction would be most appreciated.
Many thanks.
Hi guys I appreciate all the comments. I wasn't very clear with the end requirements. I want to be able to call this procedure via an anonymous block so that the user will enter a model type (&vairalbe) and the procedure will display how many of that model types are in the database.
When dealing with this type of problems, first think about the data you're trying to capture.
Dealing with implicit cursors in PL/SQL require 1-row, so you need to make sure you understand the data.
In this case, you pass in a variable that you don't use in any of your queries, so I suggest you re-evaluate.
I don't have a database at hand to run this, but you should be able to work this out and hopefully get you a bit closer. I put it in an anonymous block so that I can write it really quick.
DECLARE
PROCEDURE model_details_sp (p_model IN VARCHAR2, p_noofcars OUT NUMBER)
IS
p_description VARCHAR2 (200);
BEGIN
--2
SELECT COUNT (model_name)
INTO p_noofcars
FROM i_car
WHERE model_name = p_model;
DBMS_OUTPUT.put_line ('No of Cars for model: ' || p_noofcars);
--3
SELECT model_description
INTO p_description
FROM i_car --the table should be the car_model table so that only one record is returned
WHERE model_name = p_model;
DBMS_OUTPUT.put_line ('Model Desc' || p_description);
END model_details_sp;
BEGIN
dbms_output.put_line('');
END;
To #David Aldridge comment:
Try running this--the result should be a failure--as you cannont select multiple rows using the into CLAUS, unless you aggregate the data:
DECLARE
p_num NUMBER;
BEGIN
SELECT LEVEL INTO p_num FROM DUAL CONNECT BY LEVEL <= 10;
dbms_output.put(p_num);
END;
The error you should see is this:
Error report:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
From the description and subsequent comments, this is the solution I would provide:
DECLARE
PROCEDURE model_details_sp
(p_model IN VARCHAR2,
p_noofcars OUT NUMBER)
IS
BEGIN
SELECT COUNT(*)
INTO p_noofcars
FROM i_car
WHERE model_name = p_model;
END;
no_of_cars NUMBER := 0;
BEGIN
model_details_sp(:model_name, no_of_cars);
dbms_output.put_line('no of cars for ' || :model_name || ' = ' || no_of_cars);
END;
I've created the PROCEDURE in-line but you can just as easily extract this to the database by removing it from the declare section and executing it with CREATE OR REPLACE.
This example assumes use of an IDE that supports bind variable replacement (:model_name) on execute of the anonymous block. In TOAD, for example, the "user" will be prompted to provide a value for :model_name.
I get the following error, even though I have checked the code carefully. I don't know what I'm missing.
LINE/COL ERROR
31/1 PLS-00103: Encountered the symbol "END" when expecting one of the
following:
CODE:
CREATE OR REPLACE PROCEDURE sp_ssjm_newworkorder
( workorderno IN NUMBER,
company IN CHAR,
attention IN CHAR,
datedue IN DATE,
loggedby IN CHAR
)
AS id NUMBER;
today DATE:=SYSDATE;
BEGIN
SELECT client_id --grab client_id
INTO id
FROM ssjm_client
WHERE ssjm_client.name=company;
IF id IS NULL THEN --check if client exists by checking if client_id is there
dbms_output.put_line('Please create client first');
GOTO the_end;
ELSE
INSERT INTO ssjm_workorder VALUES(workorderno,workorderno,company,loggedby,attention,'Received',today,datedue,id);
END IF;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20999,'An error occured in' ||
SQLCODE || '-ERROR-' || SQLERRM);
<<the_end>>
END sp_ssjm_newworkorder;
There are several spots in your code needed attention:
The reason you've got that error is because label <<the_end>> should be placed before the EXCEPTION section.
Operator is required after a label. So if you want to jump to the end of a stored procedure and no other actions required NULL operator should be used.
To that end your code should look like this:
IF id IS NULL THEN --check if client exists by checking if client_id is there
dbms_output.put_line('Please create client first');
GOTO the_end;
ELSE
INSERT INTO ssjm_workorder
VALUES(workorderno,workorderno,company,loggedby
,attention,'Received',today,datedue,id);
END IF;
<<the_end>>
NULL;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20999,'An error occured in' ||
SQLCODE || '-ERROR-' || SQLERRM);
END sp_ssjm_newworkorder;
By all means try to avoid unconditional branching. Using GOTO operator is very, very not good practice. It kills readability, code like that hard to debug. It will cause you and everybody who will look at that code after you a headache. Moreover if the query
SELECT client_id --grab client_id
INTO id
FROM ssjm_client
WHERE ssjm_client.name=company;
returns no rows the exception NO_DATA_FOUND will be immediately raised and execution of the code halts. So IF id IS NULL THEN condition will never be evaluated. You may rewrite your code by removing that condition and adding NO_DATA_FOUND exception handler in the EXCEPTION section of your code. And of course as #Rob van Wijk correctly pointed out in the comment
but code can be cleaned up further. today variable can be removed and
the WHEN OTHERS should definitely be removed. As it is now, it just
transforms an error to a longer error message without more detail and
most importantly: it disguises the line number where the real error
took place.
there is no need of today variable, SYSDATE can be used directly in the values clause of the insert statement, and WHEN OTHERS can be removed as well.
CREATE OR REPLACE PROCEDURE sp_ssjm_newworkorder
(
workorderno IN NUMBER,
company IN CHAR,
attention IN CHAR,
datedue IN DATE,
loggedby IN CHAR
)
AS
id NUMBER;
BEGIN
SELECT client_id --grab client_id
INTO id
FROM ssjm_client
WHERE ssjm_client.name=company;
INSERT INTO ssjm_workorder
VALUES(workorderno,workorderno,company,loggedby
,attention,'Received',SYSDATE,datedue,id);
EXCEPTION
when NO_DATA_FOUND
then dbms_output.put_line('Please create client first');
END sp_ssjm_newworkorder;