Retrieve data by user input with a message (PL/SQL) - sql

I want to how to retrieve data from the table I have added here by inserting C_Id as the user input with defined variables and exceptions. If any customer is not available it has to display a message showing "No customer found". Please help me to understand this one.
Thank you!

If it is a stored procedure (should be; it accepts a parameter) and you just want to display what you found, then this might be one option:
create or replace procedure p_test (par_c_id in customer_details.c_id%type)
is
l_row customer_details%rowtype;
begin
select *
into l_row
from customer_details
where c_id = par_c_id;
dbms_output.put_line(l_row.customer_name ||', '||
l_row.address ||', '||
to_char(l_row.date_of_joined, 'dd.mm.yyyy')
);
exception
when no_data_found then
dbms_output.put_line('No customer found');
end;
/
Then run it as
set serveroutput on
begin
p_test(121);
end;
/
What does it do?
accepts a parameter
declares local variable which is equal to table's rowtype
select everything into the variable
using dbms_output.put_line, display elements you want
if nothing has been found, exception (no_data_found) is raised and handled in a way that you display appropriate message
Note that such an option works if tool you use (e.g. SQL*Plus, SQL Developer, TOAD, ...) allow displaying result of dbms_output.put_line. Otherwise, if you use e.g. Oracle Apex, procedure will still work, but you won't see anything.

Related

Trigger for the nexval in a sequence returing ORA-01403

I have a page in Apex where the user can connect a row from a table to another (a mail to the address) because we changed how we store addresses so we are connecting the two tables while working on them.
The link between the tables is a row in a third table that has 5 columns (ID||ID_RACC||ID_INDIRIZZO||DATA_INS||USER_INS), where ID is the main ID of the link-table, ID_RACC is the ID of the mail's table and ID_INDIRIZZO is the ID of the addresses' table.
If I try from the shell to run this query:
INSERT INTO INSERT INTO INDIRIZZI_RACCOMANDATE (ID_RACC, ID_INDIRIZZO, USER_INS, DATA_INS)
VALUES (p_id_racc, p_id_indirizzo, v('USER'), SYSDATE);
with p_id_racc, p_id_indirizzo non-empty variables, I don't have any problem.
But if the user select from a Select List the address and click the Save button from a specific page he/she receives
ORA-01403: no data found
the only code that is run from him/her is the above one.
I searched and I found out that the problem could be the trigger that fills the ID column in the table INDIRIZZI_RACCOMANDATE from a sequence.
The trigger code is:
create or replace trigger "BI_INDIRIZZI_RACCOMANDATE"
BEFORE
insert on "INDIRIZZI_RACCOMANDATE"
for each row
begin
if :NEW."ID" is null then
select "INDIRIZZI_RACCOMANDATE_SEQ".nextval into :NEW."ID" from sys.dual;
end if;
end;​
I can't understand how is it possible to have a no_data_found with only a select nextval from a sequence.
Then I can't understand how is it possible that I have this problem only if I run it from that page and don't have it if I run the exact same code from shell.
But if the user select from a Select List the address and click the Save button from a specific page he/she receives ORA-01403: no data found
While in Apex, use :APP_USER:
INSERT INTO INSERT INTO INDIRIZZI_RACCOMANDATE
(ID_RACC, ID_INDIRIZZO, USER_INS, DATA_INS)
VALUES
(p_id_racc, p_id_indirizzo, :APP_USER, SYSDATE);
^^^^^^^^^
this
By the way, v('USER') is suspicious; should have been v('APP_USER'), I presume.
V (an absolutely abhorrent object name Oracle should know better) is defined as a collection indexed by varchar2. Your problem is that 'USER' is not a valid index value for V. When a collection does not contain the referenced index value on a collection Oracle throws NO DATA FOUND. A bad choice but the one they made. That is how you get that error. use v('APP_USER'); See fiddle and below.
declare
type example_att
is table of varchar2(30)
index by varchar2(8);
example_data example_att;
begin
dbms_output.enable;
example_data('A') := 'Abcd';
example_data('E') := 'Efgh';
example_data('I') := 'Ijlk';
dbms_output.put_line( 'value for ''A'' is ' );
dbms_output.put_line( example_data('A') );
-- OOPS
dbms_output.put_line( 'value for ''L'' is ' );
dbms_output.put_line( example_data('L'));
end;
/
I had the same error message for a procedure I would call in a dynamic action. The Procedure takes two arguments where one is the APP_USER.
BOOKMARK_FAVORITE(v('CARD_ID'), v('APP_USER'));
In my Procedure I would then select the User_ID for this specific APP_USER. And here is where the error was. The username I was selecting was not in Uppercase but the APP_USER was (IN_USERNAME). So I had to use the UPPER function:
select au.user_id into IN_USER_ID
from app_user au
where UPPER(au.username) = IN_USERNAME; --IN_USERNAME = APP_USER
^^^^^
Apparantly once the user log's in, the username will be stored in APP_USER in UPPERCASE, irrespective of how user has entered in log-in screen.
Don't know if this will help in your situation though :/

Oracle stored procedure not working PLS-00306

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.

Delphi SQL how to add data into a specific record in a MS Access Database table

I am busy making an important IT Project for my class and I am struggling to succeed trough this one problem.
The program needs to Store Images to the table of the database,
but I am trying to use a different technique. When the user uses the 'loadfromfile' control, the directory of the File Name is used instead of saving the Picture itself into the database. So I have a field in the table called : "Directory" that only reads a string and I am storing the File name path into that field, like 'C:/Pictures/Picture.JPG' etc.
I use sName by an edit.text to let the user find the specific record to save the path to the field. And sDirectory for the path name itself.
I use a MS Access database table.
In the table fields : (ID, Real Name,
Surname,Pass,Age,Directory,Medium,Location,Artwork Name)
Once the user chooses the Picture from the Loadfromfile dialogue, the user needs to save the path into the specific record that the user wants to save.
I tried using this code but it keeps giving me a Syntax error :
Syntax error(missing operator) in query expression 'Username = 'the Name' Insert (Directory) Values(?)'
procedure TfrmPost.btnBrowseClick(Sender: TObject);
begin
opdImage.Execute;
sDirectory := opdImage.FileName;
MyPic.Picture.LoadFromFile(sDirectory);
bitBtnUpload.Enabled := true;
end;
procedure TfrmPost.bitBtnUploadClick(Sender: TObject);
begin
sName := lblName.Caption;
sDirectory := QoutedStr(opdImage.Filename);
with dmArt do
begin
qryArt.Close;
qryArt.SQL.Clear;
qryArt.SQL.Text := 'SELECT * FROM tbArt WHERE Username = '''+sName + ''' ';
qryArt.Open;
qryArt.SQL.Add('Insert');
qryArt.SQL.Add('(Directory)');
qryArt.SQL.Add('Values (:Directory)');
qryArt.Parameters.ParamByName('Directory').Value := sDirectory;
qryArt.ExecSQL;
qryArt.Close;
end;
end;
Insert INTO tbArt is what you're looking for to correct the error.
That's if you want to insert the sDirectory value directly into the database.
It looks like you think that the insert will happen into qryArt. It won't do that.
You want to
qryArt.Edit;
qryArt.FieldByName('directory').AsString := sDirectory;
qryArt.Post;
if you want to edit the value of the directory field in the current record. That also might (not) edit the value in the database. It all depends on what kind of component qryArt is.
Stop concatenating SQL. It leaves you open to SQL injection attacks, and makes things very difficult when trying to quote strings correctly or get date formats right. Use SQL parameters instead, and use an UPDATE statement with a WHERE clause. You can also easily test for success or failure.
procedure TfrmPost.bitBtnUploadClick(Sender: TObject);
begin
with dmArt do
begin
qryArt.Close;
qryArt.SQL.Text := 'UPDATE tbArt SET Directory = :Directory'#13 +
'WHERE UserName := :UserName';
qryArt.Parameters.ParamByName('UserName').AsString := lblName.Caption;
qryArt.Parameters.ParamByName('Directory').AsString := opdImage.FileName;
if qryArt.ExecSQL <> 1 then
raise Exception.Create('UPDATE failed. Is username correct?');
end;
end;
As an aside, your code to get the filename isn't very well designed. It does not properly handle the user cancelling the file selection dialog. Try something like this instead:
procedure TfrmPost.btnBrowseClick(Sender: TObject);
begin
if opdImage.Execute then
begin
MyPic.Picture.LoadFromFile(opdImage.FileName);
bitBtnUpload.Enabled := True;
end;
end;

PL/SQL Exception handling and update statements

I'm quite new to PL/SQL and I have a problem with displaying my exceptions that I can't seem to figure out.
I'm using two stored procedures and an anonymous block to call them. I've made a few other procedures in this manner and they all work just fine.
This is the first procedure that is updating my table.
create or replace procedure UPD_CUST_SALESYTD_IN_DB (pcustid number, pamt number) AS
err_pamt exception;
err_pcustid exception;
vcount number;
begin
select count(*) into vcount from customer where
custid = pcustid;
if vcount = 0 then raise err_pcustid;
end if;
if pamt <-999.99 or pamt >999.99 then raise err_pamt;
end if;
update customer set sales_ytd = sales_ytd + pamt
where custid = pcustid;
exception
when err_pcustid then
RAISE_APPLICATION_ERROR(-20031, 'Customer ID not found');
when err_pamt then
RAISE_APPLICATION_ERROR(-20032, 'Amount out of range');
when others then
RAISE_APPLICATION_ERROR(-20000, SQLERRM);
end;
This is the procedure that calls the above procedure. This is just displaying what I'm going to do and confirms that it worked.
create or replace procedure UPD_CUST_SALESYTD_VIASQLDEV (pcustid number, pamt number) AS
begin
dbms_output.put_line('--------------------------------------------');
dbms_output.put_line('Updating SalesYTD. Customer Id: ' || pcustid || ' Amount: ' || pamt);
UPD_CUST_SALESYTD_IN_DB(pcustid, pamt);
commit;
dbms_output.put_line('Udpate OK');
exception
when others then
RAISE_APPLICATION_ERROR(-20000, SQLERRM);
end;
This is the anonymous block I'm using to call the above procedure which then calls the one above that.
set serveroutput on;
begin
UPD_CUST_SALESYTD_VIASQLDEV(3,999.9);
end;
If I pass parameters that would not give me an error, all the code works just fine.
For example, if I input;
set serveroutput on;
begin
upd_cust_salesytd_viasqldev(3,400);
end;
I get the correct output and the changes have been made in the table.
--------------------------------------------
Updating SalesYTD. Customer Id: 3 Amount: 400
Udpate OK
However, if I pass parameters that would result in an error, either a customer id not existing or the amount being out of the range, nothing happens.
I get this:
--------------------------------------------
Updating SalesYTD. Customer Id: 3 Amount: 1000
Nothing else.
In similar procedures my exceptions are working just fine. This example is using a procedure that inserts into a table.
--------------------------------------------
Adding Customer. ID: 500 Name: Helen Nolan
ORA-20002: Customer ID out of range
I'm not sure why this procedure is not returning my exceptions at all. In my other procedures that work, if an exception is raised, the script output in Oracle SQL Developer just displays my exception.
However, in my update procedure, if something should raise an exception, above the dbms output lines, the script output prints this error report
Error report -
ORA-20000: ORA-20032: Amount out of range
ORA-06512: at "S4931645.UPD_CUST_SALESYTD_VIASQLDEV", line 10
ORA-06512: at line 2
20000. 00000 - "%s"
*Cause: The stored procedure 'raise_application_error'
was called which causes this error to be generated.
*Action: Correct the problem as described in the error message or contact
the application administrator or DBA for more information.
So it's acknowledging there that my exception has been raised, but isn't shown.
Any help is greatly appreciated, I'm thoroughly confused by this. Am I making some truly obvious mistake?
Not an expert here — just helping brainstorm. It sounds like you are getting a response but you just need to write a custom error statement. Out of range means that in the list that was selected with parameters set that it does not exist within the scope of that query. For example if list was 0-100 then response was from 0-10 and 0 was not found in that range.

Oracle Stored Procedure 'Learnings' issue

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.