How to write a procedure to square a number in oracledb - sql

CREATE OR REPLACE PROCEDURE sqr(n IN NUMBER, res OUT NUMBER)
IS
BEGIN
res:= n*n;
Dbms_Output.PUT_LINE(res);
Dbms_Output.PUT_LINE('PL/SQL procedure successfully completed');
END;
/
DECLARE
ans NUMBER;
BEGIN
EXECUTE sqr(15, :ans);
END;
/
I'm new to SQL, trying to create a query to square a number using procedure i dont know how to do it. i was able to come with code above but for some reason i cant connect to DB!
Help needed. (ignore if there are any mistakes in my que framing)

Code you wrote is ... well, not that bad. With some changes, it works:
SQL> SET SERVEROUTPUT ON
SQL> CREATE OR REPLACE PROCEDURE sqr(n IN NUMBER, res OUT NUMBER)
2 IS
3 BEGIN
4 res:= n*n;
5 END;
6 /
Procedure created.
SQL> DECLARE
2 ans NUMBER;
3 BEGIN
4 sqr(15, ans);
5 Dbms_Output.PUT_LINE(ans);
6 END;
7 /
225
PL/SQL procedure successfully completed.
Though, you'd rather create a function (instead of a procedure):
SQL> create or replace function f_sqr (n in number)
2 return number
3 is
4 begin
5 return n*n;
6 end;
7 /
Function created.
SQL> select f_sqr(15) ans from dual;
ANS
----------
225
SQL>
But, nothing of that matters because you said
for some reason i cant connect to DB!
That's the real problem, and you shared absolutely no information about it. Which tool did you use? Do you have a database at all? Where is it? On your own computer or on a server (available to you through the network)? How exactly did you try to connect? What did Oracle say?

Related

Trying to create stored procedure in Oracle SQL

I'm trying to create a procedure in Oracle. I want to be able to call on the procedure with a variable input and have a statement read. I am in the process of learning Oracle SQL, so I'm not sure where I'm going wrong.
This is my code:
create or replace procedure gradeCheck(grade char(1))
Begin
Case
When grade = 'A' then DBMS_OUTPUT.PUT_LINE('Great Work')
else DBMS_OUTPUT.PUT_LINE('Not great work')
end case;
end gradeCheck;
/
Begin
gradeCheck(A);
end;
/
I want the input to be 'A' (the grade assignment) and to get the text output. I am getting a message that the GRADECHECK procedure is being compiled. But it won't let me call it with an input.
You want use IF not CASE
You are missing the IS keyword before BEGIN
You need to terminate statements with ;
The CHAR data type does not have a length in the signature.
Like this:
create procedure gradeCheck(
grade CHAR
)
IS
BEGIN
IF grade = 'A' THEN
DBMS_OUTPUT.PUT_LINE('Great Work');
ELSE
DBMS_OUTPUT.PUT_LINE('Not great work');
END IF;
END gradeCheck;
/
Then you need to use quotes around the string:
Begin
gradeCheck('A');
end;
/
db<>fiddle here
Your issues
You are missing a word is in the create or replace statement
If the input variable is string ( char ) then you have to enclose in quotes the value when you call the procedure.
Use varchar2 instead of char, although it is not mandatory.
; must be at the end of dbms_output
If you run it with sqlplus, use set serveroutput on to enable the output, that you can see the message.
Then
create or replace procedure gradeCheck(grade in varchar2)
is
Begin
case when grade = 'A'
then
DBMS_OUTPUT.PUT_LINE('Great Work');
else
DBMS_OUTPUT.PUT_LINE('Not great work');
end case;
end gradeCheck;
/
set serveroutput on
Begin
gradeCheck('A');
end;
/
Test Case
SQL> l
1 create or replace procedure gradeCheck(grade in varchar2)
2 is
3 Begin
4 case
5 when grade = 'A' then
6 DBMS_OUTPUT.PUT_LINE('Great Work');
7 else
8 DBMS_OUTPUT.PUT_LINE('Not great work');
9 end case;
10* end gradeCheck;
SQL> /
Procedure created.
SQL> begin
2 gradeCheck('A');
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> set serveroutput on
SQL> r
1 begin
2 gradeCheck('A');
3* end;
Great Work
PL/SQL procedure successfully completed.

is there a function without an input but return something

CREATE OR REPLACE FUNCTION FN_MULTAS_TOTAL
RETURN INTEGER
IS
V_TOTAL INT;
BEGIN
SELECT SUM(MULTA)
INTO V_TOTAL
FROM DETALLE_ARRIENDO;
RETURN V_TOTAL;
END;
im working on SQL Developer 11 and i have to call it with
exec FN_MULTAS_TOTAL;
and get an integer value
No problem with such a function:
SQL> create or replace function fn_multas_total
2 return integer
3 is
4 v_total int;
5 begin
6 select sum(multa)
7 into v_total
8 from detalle_arriendo;
9 return v_total;
10 end;
11 /
Function created.
However, you don't call it with exec - it is used in SQL*Plus or SQL Developer or some other tools which support it; it is a "shortcut" for an anonymous begin-end PL/SQL block:
SQL> exec p_test
PL/SQL procedure successfully completed.
SQL> begin
2 p_test;
3 end;
4 /
PL/SQL procedure successfully completed.
It is used for procedures, not functions. You can't just
SQL> begin
2 detalle_arriendo;
3 end;
4 /
detalle_arriendo;
*
ERROR at line 2:
ORA-06550: line 2, column 3:
PLS-00221: 'DETALLE_ARRIENDO' is not a procedure or is undefined
ORA-06550: line 2, column 3:
PL/SQL: Statement ignored
SQL>
which means that you have to declare a variable and fetch function's result into it, e.g.
SQL> declare
2 l_result number;
3 begin
4 l_result := fn_multas_total;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
Usually, we use functions as
SQL> select fn_multas_total from dual;
FN_MULTAS_TOTAL
---------------
100
SQL>
If you desperately want to use exec, then you still have to declare a variable and
SQL> var result number
SQL> exec :result := fn_multas_total;
PL/SQL procedure successfully completed.
SQL> print :result
RESULT
----------
100
SQL>

DYNAMIC SQL FOR TABLE NAME AT RUN TIME

create or replace procedure ankit
(table_name varchar2)
is
begin
dbms_output.put('select NAME FROM '||table_name);
end;
begin
ankit('ITEM');
end;
I am trying to execute the above command and it's compiling successfully but I am not able to see the output for the same.
If you are doing it in SQL*Plus, then SET SERVEROUTPUT ON is what you need to do first.
If you are using any GUI based client tool, then check the option to enable dbms_output
And use, DBMS_OUTPUT.PUT_LINE
Edit : See this test case.
SQL> set serveroutput on;
SQL>
SQL> create or replace procedure ankit
2 (table_name varchar2)
3 is
4 BEGIN
5 dbms_output.put_line('select NAME FROM '||table_name);
6 END;
7 /
Procedure created.
SQL>
SQL> begin
2 ankit('ITEM');
3 end;
4 /
select NAME FROM ITEM
PL/SQL procedure successfully completed.
SQL>
you have to enable output before running the code in SQL * PLUS
set serveroutput on ;

oracle - mixing SQL code with PLSQL when no bindings in WHERE statement

I am trying to write a very simple sql script:
select * from table_X;
and I would like to see the results in oracle sqlplus, if there are any. These results are important for further analysis.
Also to mention, it depends, how many tables were created originally, so chances are that table_X may not be in the database at all. However I want to avoid getting an error, when parsing, that table_X doesn't exist, while running that script above.
So I was trying to wrap that SQL into some PLSQL dynamic code, like this:
Define table_X="MY_TAB"
DECLARE
stmt_ VARCHAR2(2000);
exist_ number := 0;
CURSOR table_exist IS
SELECT 1
FROM user_tables
WHERE table_name = '&table_X';
BEGIN
OPEN table_exist;
FETCH table_exist INTO exist_;
CLOSE table_exist;
IF exist_ = 1 THEN
stmt_ := 'SELECT * FROM &table_X';
EXECUTE IMMEDIATE stmt_;
ELSE
dbms_output.put_line('This functionality is not installed.');
END IF;
END;
/
Why I cannot see any result (records), if there is data in MY_TAB? Do I really need to bind some columns and use ex. dbms_output to be able to see some information?
Is there any simple way to query a table without getting 'ORA-00942: table or view does not exist'
if that table doesn't exist (ideally using SQL only)?
Thanks in advance
like this if you want it in sqlplus:
SQL> var c refcursor;
SQL> create or replace function get_table(p_tab in varchar2)
2 return sys_refcursor
3 is
4 v_r sys_refcursor;
5 NO_TABLE exception;
6 pragma exception_init(NO_TABLE, -942);
7 begin
8 open v_r for 'select * from ' || dbms_assert.simple_sql_name(p_tab);
9 return v_r;
10 exception
11 when NO_TABLE
12 then
13 open v_r for select 'NO TABLE ' || p_tab as oops from dual;
14 return v_r;
15 end;
16 /
Function created.
SQL> exec :c := get_table('DUAL2');
PL/SQL procedure successfully completed.
SQL> print c
OOPS
-----------------------------------------
NO TABLE DUAL2
SQL>
SQL> exec :c := get_table('DUAL');
PL/SQL procedure successfully completed.
SQL> print c
D
-
X
Instead of execute immediate 'query' you could use execute immediate 'query' bulk collect into and then loop over it and use dbms_output to print it.
http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/executeimmediate_statement.htm

Strange behavior with large Object Types

I recognized that calling a method on an Oracle Object Type takes longer when the instance gets bigger.
The code below just adds rows to a collection stored in the Object Type and calls the empty dummy-procedure in the loop.
Calls are taking longer when more rows are in the collection. When I just remove the call to dummy, performance is much better (the collection still contains the same number of records):
Calling dummy: Not calling dummy:
11 0
81 0
158 0
Code to reproduce:
Create Type t_tab Is Table Of VARCHAR2(10000);
Create Type test_type As Object(
tab t_tab,
Member Procedure dummy
);
Create Type Body test_type As
Member Procedure dummy As Begin
Null; --# Do nothing
End dummy;
End;
Declare
v_test_type test_type := New test_type( New t_tab() );
Procedure run_test As
start_time NUMBER := dbms_utility.get_time;
Begin
For i In 1 .. 200 Loop
v_test_Type.tab.Extend;
v_test_Type.tab(v_test_Type.tab.Last) := Lpad(' ', 10000);
v_test_Type.dummy(); --# Removed this line in second test
End Loop;
dbms_output.put_line( dbms_utility.get_time - start_time );
End run_test;
Begin
run_test;
run_test;
run_test;
End;
I tried with both 10g and 11g.
Can anyone explain/reproduce this behavior?
I can reproduce the behavior on my 11.1.0.7 database. I'm not certain that I have an explanation, but I do have a theory.
If you move the Extend call outside the loop and just add 200 elements to the collection, the decrease in performance disappears (see below). That leads me to believe that it is not solely the act of calling the object method that is the problem-- there appears to be some interaction with the inefficient extension of the collection by 1 element 200 times rather than by 200 elements 1 time.
SQL> ed
Wrote file afiedt.buf
1 Declare
2 v_test_type test_type := New test_type( New t_tab() );
3 Procedure run_test As
4 start_time NUMBER := dbms_utility.get_time;
5 Begin
6 v_test_Type.tab.Extend(200);
7 For i In 1 .. 200 Loop
8 v_test_Type.tab(v_test_Type.tab.Last) := Lpad(' ', 10000);
9 v_test_Type.dummy(); --# Removed this line in second test
10 End Loop;
11 dbms_output.put_line( dbms_utility.get_time - start_time );
12 End run_test;
13 Begin
14 run_test;
15 run_test;
16 run_test;
17* End;
SQL> /
11
9
10
PL/SQL procedure successfully completed.
Speculating here, but perhaps there is some optimization that the compiler is able to make to the calls to extend the collection that it cannot (or does not) make if a call to a procedure might modify the collection.
As a quick test of that speculation, I created a member function rather than a member procedure and called the function in the loop. Since functions don't modify object state, they wouldn't preclude the sort of optimizations I was speculating about. Sure enough, if I create the object type with a member function, the decline in performance disappears
SQL> ed
Wrote file afiedt.buf
1 Create or replace Type test_type As Object(
2 tab t_tab,
3 Member Procedure dummy,
4 Member Function dummy2 return number
5* );
SQL> /
Type created.
SQL> ed
Wrote file afiedt.buf
1 Create or replace Type Body test_type As
2 Member Procedure dummy As Begin
3 Null; --# Do nothing
4 End dummy;
5 Member Function dummy2
6 return number
7 Is
8 Begin
9 Return 1;
10 End dummy2;
11* End;
12 /
Type body created.
SQL> ed
Wrote file afiedt.buf
1 Declare
2 v_test_type test_type := New test_type( New t_tab() );
3 Procedure run_test As
4 start_time NUMBER := dbms_utility.get_time;
5 l_num NUMBER;
6 Begin
7 For i In 1 .. 200 Loop
8 v_test_Type.tab.Extend;
9 v_test_Type.tab(v_test_Type.tab.Last) := Lpad(' ', 10000);
10 l_num := v_test_Type.dummy2(); --# Removed this line in second test
11 End Loop;
12 dbms_output.put_line( dbms_utility.get_time - start_time );
13 End run_test;
14 Begin
15 run_test;
16 run_test;
17 run_test;
18* End;
19 /
11
9
9
PL/SQL procedure successfully completed.
In the end, it looks to me like the problematic statement is the Extend but that the optimizer is smart enough to be able to avoid the penalty if nothing in the loop is able to modify the object.
Found out myself, the problem is described in Using SELF IN OUT NOCOPY with Member Procedures:
In member procedures, if SELF is not declared, its parameter mode defaults to IN OUT.
So with every procedure call my whole object was copied twice, and as size was increasing this took longer and longer.
The solution is to use SELF IN OUT NOCOPY test_type as first parameter of my procedure declaration:
Create Type test_type As Object(
tab t_tab,
Member Procedure dummy(SELF IN OUT NOCOPY test_type)
);
and is still called without parameter
v_test_type.dummy();
Performance is back to normal:
0
0
0