PL/SQL procedure successfully completed, but when I want to display Max(DEPARTMENT_ID), can anyone pls suggest? - plsql

Max(DEPARTMENT_ID), can anyone Please suggest
<set serveroutput on;
DECLARE
v_max_deptno DEPARTMENTS.DEPARTMENT_ID%TYPE;
BEGIN
SELECT Max(department_id)
INTO v_max_deptno
FROM departments
Where department_id = v_max_deptno;
DBMS_OUTPUT.PUT_LINE('The maximum department_id is: '|| v_max_deptno);
END;/>

This declaration:
v_max_deptno DEPARTMENTS.DEPARTMENT_ID%TYPE;
is for a local variable. Since you provide no default value and it is never assigned any value, it defaults to NULL.
This predicate in the SQL query:
Where department_id = v_max_deptno
means that the query should only return rows where the department_id is equal to the value in that variable. Since the variable is NULL, and since no value can equal NULL, the query returns no rows.
Since your query is based on a simple aggregate (MAX), the query returns without error. Since there were no rows, the MAX function returns NULL back into the same variable again.
For further assistance, you need to explain what the purpose of your code is and what value you expect to get. If you need the maximum department_id currently in the table across all rows, you would simply remove the where clause.
Note: if your purpose in finding the current maximum ID is to set the department_id for a new record, there are some other issues with this approach (to do with concurrent sessions) that you need to consider.

Your query doesn't make much sense, as it is trying to find the MAX(department_id) (and put its value into the V_MAX_DEPTNO variable), while the same variable is used in the WHERE clause.
At the time of declaration, V_MAX_DEPTNO is NULL, it is NULL in the WHERE clause as well, and no department's ID is "equal" to NULL, so that query returns nothing.
If you initialized the V_MAX_DEPTNO (which is, of course, stupid), you'd get something:
SQL> DECLARE
2 v_max_deptno departments.department_id%TYPE := 20;
3 BEGIN
4 SELECT MAX (department_id)
5 INTO v_max_deptno
6 FROM departments
7 WHERE department_id = v_max_deptno;
8
9 DBMS_OUTPUT.put_line ('The maximum department_id is: ' || v_max_deptno);
10 END;
11 /
The maximum department_id is: 20
PL/SQL procedure successfully completed.
SQL>
So the question is: what are you trying to do? In my opinion, the right way to do it is to remove this WHERE clause, i.e.
SQL> DECLARE
2 v_max_deptno departments.department_id%TYPE := 20;
3 BEGIN
4 SELECT MAX (department_id)
5 INTO v_max_deptno
6 FROM departments;
7
8 DBMS_OUTPUT.put_line ('The maximum department_id is: ' || v_max_deptno);
9 END;
10 /
The maximum department_id is: 40
PL/SQL procedure successfully completed.
SQL>

Related

PLSQL Return Sequence.currval When Sequence Name Is Built Using Substitution Strings

I would like to use the same application in different instances so I need to specify the workspace and sequence ID.
Example query
BEGIN
INSERT INTO STEP (STEP_CHART_TITLE)
VALUES ('Action', 'Action');
RETURN '"'||:v_workspace||'"."'||:v_seqid||'".currval';
END;
If I use:
"FREEADMIN"."ISEQ$$_111997".currval;
in the return statement it works fine.
If I use the substitution strings, it will build the string correctly, but won't return the sequence number.
Is there a way to get the sequence number?
Thanks
"PL/SQL" as Oracle's procedural extension to SQL? Asking because I don't quite understand what "workspace" represents (we call it a "user" or a "schema" or even "owner" in Oracle).
If so, then you can't fetch current value unless you first fetch next sequence value (you didn't post whole code you use so I'm not sure whether you did that or not; also, insert statement is wrong - you're inserting 2 values into a single column).
SQL> select seq.currval from dual;
select seq.currval from dual
*
ERROR at line 1:
ORA-08002: sequence SEQ.CURRVAL is not yet defined in this session
SQL> select seq.nextval from dual;
NEXTVAL
----------
6
SQL> select seq.currval from dual;
CURRVAL
----------
6
SQL>
Therefore, the whole code might look like this - you'd use dynamic SQL. As this is SQL*Plus, I'm using substitution variables; you'd use bind variables (i.e. :v_workspace instead of '&v_workspace') (if that's what you're doing). This code just displays the value - you'd return it.
SQL> create table step (id number, step_chart_title varchar2(10));
Table created.
SQL> declare
2 l_str varchar2(200);
3 l_id number;
4 begin
5 l_str := 'select ' || '&v_workspace' ||'.'|| '&v_seqid' ||'.nextval from dual';
6 execute immediate l_str into l_id;
7
8 insert into step (id, step_chart_title) values (l_id, 'Action');
9
10 dbms_output.put_line(l_id); --> L_ID now contains CURRVAL
11 end;
12 /
Enter value for v_workspace: scott
Enter value for v_seqid: seq
8 --> here it is
PL/SQL procedure successfully completed.
SQL>

Find a column and a value from a schema scan all the table in oracle

I am trying to find a column (ABC) and it's value 1234 from a schema , basically i need to to check if ABC and a value from this column 1234 is present in any other table that is mapped to ABC , i tried to do a search the most efficient way but it is taking lot of time and not retrieving the desired result
i have tried
https://lalitkumarb.wordpress.com/2015/01/06/sql-to-search-for-a-value-in-all-columns-of-all-atbles-in-an-entire-schema/
but the query is not results at all it is running running...
You may write the output to a file if you get buffer overflow on set Serveroutput otherwise this should do.Output will have all tables that has 'ABC' column and respective count shows count of record with ABC column value as 1234.
SET SERVEROUTPUT ON 100000
DECLARE
lv_count number(10):=0;
l_str varchar2 (1000);
BEGIN
FOR V1 IN
(select distinct table_name
from dba_tab_columns
where column_name = 'ABC')
LOOP
BEGIN
lv_query := ' select count(*) from '||v1.table_name||' where ABC =1234';
EXECUTE IMMEDIATE lv_query INTO lv_count;
dbms_output.put_line(v1.table_name||' --> '||lv_count);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('OTHERS EXCEPTION '||v1.table_name||' ERRCODE '||SQLERRM||' '||SUBSTR(SQLCODE,1,200));
END;
END LOOP;
END;
To find all tables having column_name ABC, simple query as below should do.
select table_name
from dba_tab_columns
where column_name = UPPER('ABC');
PS: Metadata tables(dba_Tab_columns) stores column_name in upper case, to avoid any issues with case ,converting the case to upper for the literal.
Second query in PL/SQL block,
SET SERVEROUTPUT ON 100000
DECLARE
lv_count number(10):=0;
l_str varchar2 (1000);
lv_col_name varchar2(255) :='ABC';
BEGIN
FOR V1 IN
(select distinct table_name
from dba_tab_columns
where column_name = lv_col_name)
LOOP
dbms_output.put_line(lv_col_name||' '||v1.table_name);
END LOOP;
END;

Passing parameter to PL/SQL procedure using select from database

Is it possible to define a variable as current_scn:= 'select current_scn from V$database' in the declaration section of a procedure. Using the one below gives me the output. But I would like to define it in the declare section, so each time it gets executed it will get the current scn. Need to execute the procedure based on the input. Is it possible do so?
DECLARE
currnet_scn VARCHAR2(500);
BEGIN
EXECUTE IMMEDIATE 'select current_scn from V$database' INTO currnet_scn;
DBMS_OUTPUT.PUT_LINE(currnet_scn);
END;
No, you can't do it exactly as you wanted (if you could, you'd already do it, I presume).
But, you can create a function which can then be used in declare section. See how:
SQL> create or replace function f_scn
2 return number
3 is
4 retval number;
5 begin
6 select current_scn into retval from V$database;
7 return retval;
8 end;
9 /
Function created.
SQL> set serveroutput on
SQL> declare
2 current_scn number := f_scn; --> function is used here
3 begin
4 dbms_output.put_line('SCN = ' || current_scn);
5 end;
6 /
SCN = 16535194799153
PL/SQL procedure successfully completed.
SQL>
Though, now you don't need to declare anything at all:
SQL> begin
2 dbms_output.put_line('SCN = ' || f_scn);
3 end;
4 /
SCN = 16535194799171
PL/SQL procedure successfully completed.
SQL>
Your example uses dynamic SQL. Why? There's nothing dynamic in it, which means that
select current_Scn into current_scn from v$database;
works just fine.
Finally: don't name variables as column names; it causes confusion. I'd suggest to make it e.g. declare v_current_scn number;

getting Warning: Function created with compilation errors

I am getting error while executing the following function.I have been banging my head for quite sometime now.I am new to oracle so I am not able to correct it.Can someone please help?
create or replace function rever(x int)
return number
is
y varchar2(30);
c varchar2(30);
v int;
begin
y:=to_char(x);
c:=reverse(y);
v:=to_number(c);
return v;
end rever;
/
the following is showing as error message
LINE/COL ERROR
-------- -----------------------------------------------------------------
9/1 PL/SQL: Statement ignored
9/4 PLS-00201: identifier 'REVERSE' must be declared
Oracle does not provide a function in plsql to do a string reverse.
create or replace function rever(x int)
return number
is
y varchar2(30);
c varchar2(30);
v int;
begin
y:=to_char(x);
-- Loop other each char in a string from the last to the first element
for i in reverse 1.. length(y)
loop
c:= c|| substr(y,i,1);
end loop;
v:=to_number(c);
return v;
end rever;
/
Test:
begin
dbms_output.put_line(rever(1));
dbms_output.put_line(rever(12));
dbms_output.put_line(rever(21));
dbms_output.put_line(rever(123));
end;
/
Result:
dbms_output
1
21
12
321
db<>fiddle here
There is no PL/SQL reverse() function in Oracle. So this does not work:
declare
v varchar2(20);
begin
v:= reverse('krow not does ti');
dbms_output.put_line(v);
end;
/
It throws the PLS-00201 error you got.
However, there is an undocumented SQL function which we can use in PL/SQL, but only by invoking the SQL engine:
declare
v varchar2(20);
begin
select reverse('skrow ti') into v from dual;
dbms_output.put_line(v);
end;
/
Of course, because reverse() is undocumented we're not supposed to use it, at least in production code. Not sure why it's undocumented. I think Oracle uses it for reverse indexes, so maybe there's some limit on reversible string size.
Here is a db<>fiddle demo.
The performace is a bit worse
I think that is the cost of moving from the PL/SQL engine to the SQL engine and back again. So it comes down to use case. If we're writing a function which will only be used in pure PL/SQL then I think your approach is the better one. But if we're writing a function to be used in SQL then I would consider using the Oracle built-in instead, even though it's not supported.
Although to be honest I can't remember the last time I used a reverse() function - Oracle's or hand-rolled - in real life (as opposed to answering questions in forums or similar Code Golf questions :) ).
Just for amusement, without PL/SQL, using a little bit of regular expressions with hierarchical query:
SQL> with test (col) as
2 (select 'Littlefoot' from dual)
3 select listagg(one, '') within group (order by lvl desc) reversed
4 from (select level lvl, regexp_substr(col, '.', 1, level) one
5 from test
6 connect by level <= length(col)
7 );
REVERSED
--------------------------------------------------------------------------
toofelttiL
SQL>
Or, rewritten as a function:
SQL> create or replace function f_reverse (par_col in varchar2)
2 return varchar2
3 is
4 retval varchar2(1000);
5 begin
6 select listagg(one, '') within group (order by lvl desc)
7 into retval
8 from (select level lvl, regexp_substr(par_col, '.', 1, level) one
9 from dual
10 connect by level <= length(par_col)
11 );
12 return retval;
13 end;
14 /
Function created.
SQL> select empno, f_reverse(empno) rev_empno,
2 ename, f_reverse(ename) rev_ename
3 from emp
4 where rownum <= 3;
EMPNO REV_EMPNO ENAME REV_ENAME
---------- ---------- ---------- ----------
7369 9637 SMITH HTIMS
7499 9947 ALLEN NELLA
7521 1257 WARD DRAW
SQL>

Execute stored procedure error in select statement

I have a Procedure like this,
create or replace
PROCEDURE SP_PROOF
( proof_id IN NUMBER
, Type1 IN VARCHAR2
, StatementType IN NUMBER
, Resultset OUT NUMBER
) AS
BEGIN
IF StatementType = 1 Then
INSERT INTO ID_Proof (proofid,Id_type)
VALUES (proof_id, Type1);
ELSIF StatementType=2 THEN
SELECT proofid,Id_type Into Resultset FROM ID_Proof;
ELSIF StatementType=3 THEN
UPDATE ID_Proof SET Id_type = Type1 WHERE proofid = proof_id;
ELSIF StatementType=4 THEN
DELETE FROM ID_Proof WHERE proofid = proof_id;
end if;
end;
Im getting an error like this,
Error(14,1): PL/SQL: SQL Statement ignored
Error(14,64): PL/SQL: ORA-00947: not enough values
Please help me to correct the error.
Line 14 is:
SELECT proofid,Id_type Into Resultset FROM ID_Proof;
You are selecting two values, proofid and Id_type, into a single scalar variable Resultset. But you also have no filter, so even if you changed that to select a single value then you'd get a too-many-rows error if there was more than one row in the table (and no-data-found if the table is empty).
It isn't clear what you want to happen; perhaps you want select id_type into resultset from id_proof, but from the parameters id_type is a string - so selecting that into a number variable is likely to fail too. Or perhaps you want all IDs for the specified type, in which case the type of result set would need to be a table type or a ref cursor.
Having separate procedures and functions would be probably be clearer, too.

Resources