Checking of current system date in static table - oracle

I am new to pl/sql blocks..i have a requirement inside my proc as below:
I have a static data table tb_calender having column extract_date with DATE type. Want to check if the current system date is present in the table tb_calender.extract_date . If not present, exit the proc with logging error.
Please suggest on this.

A function might be more appropriate (so that you'd let the caller know whether today's date exists in the table or not). You could return a Boolean, or e.g. a number (which is simpler as you can use it in SQL, while Boolean works only in PL/SQL).
You probably don't want to check sysdate itself as it contains date AND time components (up to seconds), so ... how probable is it that table contains a value which matches right now? That's why I used TRUNC function.
Setup:
SQL> alter session set nls_date_Format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select * from tb_calender;
EXTRACT_DATE
-------------------
10.01.2022 00:00:00 --> that's today's date
08.01.2022 00:00:00
SQL> select sysdate from dual;
SYSDATE
-------------------
10.01.2022 20:34:42
Function:
SQL> create or replace function f_test_01
2 return number
3 is
4 /* Return 1 if EXTRACT_DATE which is equal to today's date exists.
5 Return 0 otherwise
6 */
7 l_cnt number;
8 begin
9 select count(*)
10 into l_cnt
11 from tb_calender
12 where extract_date = trunc(sysdate);
13
14 return case when l_cnt = 0 then 0
15 else 1
16 end;
17 end f_test_01;
18 /
Function created.
SQL> select f_test_01 from dual;
F_TEST_01
----------
1
Procedure:
SQL> create or replace procedure p_test
2 is
3 l_cnt number;
4 begin
5 select count(*)
6 into l_cnt
7 from tb_calender
8 where extract_date = trunc(sysdate);
9
10 if l_cnt = 0 then
11 dbms_output.put_line('Today''s date does not exist');
12 else
13 dbms_output.put_line('Today''s date exists');
14 end if;
15 end;
16 /
Procedure created.
SQL> set serveroutput on
SQL> exec p_test;
Today's date exists
PL/SQL procedure successfully completed.
SQL>

Related

I want to fetch column values from column name rollnoofstud of tableA using PL/SQL

DECLARE
TYPE norollno IS TABLE OF VARCHAR2(100);
rollno norollno;
BEGIN
BEGIN
SELECT token
BULK COLLECT INTO rollno
FROM tableA
WHERE columname='rollnoofstud';
EXCEPTION
WHEN NO_DATA_FOUND THEN
rollno := norollno();
END ;
IF rollno >0 THEN
FOR i IN rollno.FIRST..norollno.LAST
LOOP
<doSomeThing>
END LOOP;
END IF;
END;
I am trying this but I am not getting output. I doubt if my select statement is correct.
I don't have your table so I created one:
SQL> CREATE TABLE tablea
2 AS
3 SELECT ename AS token, 'rollnoofstud' AS columname
4 FROM emp
5 WHERE deptno = 10;
Table created.
Code you posted isn't that wrong; requires a little bit of fixing (see line #17, the way you check whether collection contains something (count it!); typo in FOR loop):
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 TYPE norollno IS TABLE OF VARCHAR2 (100);
3
4 rollno norollno;
5 BEGIN
6 BEGIN
7 SELECT token
8 BULK COLLECT INTO rollno
9 FROM tableA
10 WHERE columname = 'rollnoofstud';
11 EXCEPTION
12 WHEN NO_DATA_FOUND
13 THEN
14 rollno := norollno ();
15 END;
16
17 IF rollno.COUNT > 0
18 THEN
19 FOR i IN rollno.FIRST .. rollno.LAST
20 LOOP
21 DBMS_OUTPUT.put_line (rollno (i));
22 END LOOP;
23 END IF;
24 END;
25 /
CLARK --> here's the result
KING
MILLER
PL/SQL procedure successfully completed.
SQL>
[EDIT: with your sample table and data:]
(note that there's no text datatype in Oracle!)
SQL> CREATE TABLE students
2 (
3 rollnostud INTEGER PRIMARY KEY,
4 name VARCHAR2 (10) NOT NULL,
5 gender VARCHAR2 (1) NOT NULL
6 );
Table created.
SQL> INSERT INTO students
2 VALUES (1, 'Ryan', 'M');
1 row created.
SQL> INSERT INTO students
2 VALUES (2, 'Joanna', 'F');
1 row created.
SQL> INSERT INTO students
2 VALUES (3, 'John', 'M');
1 row created.
Procedure:
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 TYPE norollno IS TABLE OF VARCHAR2 (100);
3
4 rollno norollno;
5 BEGIN
6 BEGIN
7 SELECT name
8 BULK COLLECT INTO rollno
9 FROM students;
10 EXCEPTION
11 WHEN NO_DATA_FOUND
12 THEN
13 rollno := norollno ();
14 END;
15
16 IF rollno.COUNT > 0
17 THEN
18 FOR i IN rollno.FIRST .. rollno.LAST
19 LOOP
20 DBMS_OUTPUT.put_line (rollno (i));
21 END LOOP;
22 END IF;
23 END;
24 /
Ryan
Joanna
John
PL/SQL procedure successfully completed.
SQL>

How to update ref cursor values in oracle?

I want to fetch limited no. of rows using refcursor. then I need to update same set of records. is it possible?
create or replace PROCEDURE myproc (
P_ROWCOUNT IN NUMBER,
OUT_TXN_IDS OUT OF_CR_TYPE,
P_CD_ERROR OUT NUMBER,
P_DS_ERROR OUT VARCHAR2
)
AS
V_TXNID NUMBER;
BEGIN
P_CD_ERROR := 0;
P_DS_ERROR := 'SUCCESS';
OPEN OUT_TXN_IDS for
SELECT id FROM table1 WHERE status='N' AND ROWNUM<=P_ROWCOUNT;
EXCEPTION
WHEN OTHERS THEN
P_CD_ERROR := sqlcode;
P_DS_ERROR := 'WF-ERROR - myproc - ' || substr(SQLERRM, 1, 200);
RETURN;
END myproc;
I need to update same records to status Y after refcursor returns. can we do this. please suggest
I don't have your tables nor data so I simplified it a little bit, but - it should work nonetheless.
Initial statuses:
SQL> SELECT status, count(*) FROM table1 group by status;
S COUNT(*)
- ----------
Y 7
N 7
Procedure: basically, you'd modify rows represented by ID returned by ref cursor.
SQL> DECLARE
2 out_txn_ids SYS_REFCURSOR;
3 p_rowcount NUMBER := 5;
4 l_id table1.id%TYPE;
5 BEGIN
6 OPEN out_txn_ids FOR SELECT id
7 FROM table1
8 WHERE status = 'N'
9 AND ROWNUM <= p_rowcount;
10
11 LOOP
12 FETCH out_txn_ids INTO l_id;
13
14 EXIT WHEN out_txn_ids%NOTFOUND;
15
16 UPDATE table1
17 SET status = 'Y'
18 WHERE id = l_id;
19 END LOOP;
20
21 CLOSE out_txn_ids;
22 END;
23 /
PL/SQL procedure successfully completed.
Result:
SQL> SELECT status, count(*) FROM table1 group by status;
S COUNT(*)
- ----------
Y 12
N 2
SQL>

How to fix ORA-01422:- Fetch isnt working

I'm not understanding why this error is occurring. I have seen examples with him but the people doesn't use the for or the fetch loop. As I have understood, the fetch would loop in all the output of the cursor, in this case, taking row by row of the query and avoiding this error.
See the code:
CREATE OR REPLACE TYPE tab_dias IS TABLE OF INTEGER;
CREATE OR REPLACE FUNCTION uf_dias_internado_paciente
(v_cod_paciente IN internacao.COD_PACIENTE%TYPE,
v_dt_inicio IN internacao.DT_HORA_ENTRADA %TYPE,
v_dt_fim IN internacao.DT_HORA_ALTA %TYPE)
RETURN tab_dias
IS
v_dias tab_dias := tab_dias();
CURSOR c_dias IS
SELECT EXTRACT(DAY FROM (i.DT_HORA_ALTA - i.DT_HORA_ENTRADA)) AS dias
FROM INTERNACAO i
WHERE i.COD_PACIENTE = v_cod_paciente
AND i.DT_HORA_ENTRADA >= v_dt_inicio --13
AND i.DT_HORA_ALTA <= v_dt_fim;
linha_dias c_dias%ROWTYPE;
BEGIN
OPEN c_dias;
LOOP
FETCH c_dias INTO linha_dias;
EXIT WHEN c_dias%NOTFOUND;
v_dias(v_dias.last) := linha_dias.dias;
END LOOP;
CLOSE c_dias;
RETURN v_dias;
END;
The error: ORA-01422: exact fetch returns more than requested number of rows
The code I'm running:
SELECT uf_dias_internado_paciente (5007, CURRENT_TIMESTAMP - 500000, CURRENT_TIMESTAMP ) FROM DUAL;
The desired output:
SELECT (EXTRACT(DAY FROM (i.DT_HORA_ALTA - i.DT_HORA_ENTRADA)))
FROM INTERNACAO i
WHERE i.COD_PACIENTE = 5007
AND i.DT_HORA_ENTRADA >= CURRENT_TIMESTAMP - 500000
AND i.DT_HORA_ALTA <= CURRENT_TIMESTAMP;
(EXTRACT(DAYFROM(I.DT_HORA_ALTA-I.DT_HORA_ENTRADA)))|
----------------------------------------------------|
11|
1|
1|
Oracle documentation:
https://docs.oracle.com/cd/B14117_01/appdev.101/b10807/06_ora.htm#i36655
https://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems020.htm
Code - as you wrote it - will return
ORA-06502: PL/SQL: numeric or value error: NULL index table key value
because you're missing v_dias.EXTEND. It can't fail with ORA-01422 (which is TOO_MANY_ROWS); cursors don't return it (unless you have a subquery - which you don't).
Therefore, there's something wrong in code you posted vs. what you are saying.
As I don't have your tables, here's an example based on Scott's EMP table:
SQL> CREATE OR REPLACE TYPE tab_dias IS TABLE OF INTEGER;
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION f_dias (par_deptno IN NUMBER)
2 RETURN tab_dias
3 IS
4 v_dias tab_dias := tab_dias ();
5
6 CURSOR c_dias IS
7 SELECT empno AS dias
8 FROM emp
9 WHERE deptno = par_deptno;
10
11 linha_dias c_dias%ROWTYPE;
12 BEGIN
13 OPEN c_dias;
14
15 LOOP
16 FETCH c_dias INTO linha_dias;
17
18 EXIT WHEN c_dias%NOTFOUND;
19 v_dias.EXTEND; --> this
20 v_dias (v_dias.LAST) := linha_dias.dias;
21 END LOOP;
22
23 CLOSE c_dias;
24
25 RETURN v_dias;
26 END;
27 /
Function created.
Testing:
SQL> SELECT f_dias (10) FROM DUAL;
F_DIAS(10)
--------------------------------------------------------------------------------
TAB_DIAS(7782, 7839, 7934)
Or:
SQL> SELECT * FROM TABLE(f_dias (10));
COLUMN_VALUE
------------
7782
7839
7934
SQL>
Instead of a loop, perhaps you should consider bulk collect; it is simpler and more efficient:
SQL> CREATE OR REPLACE FUNCTION f_dias (par_deptno IN NUMBER)
2 RETURN tab_dias
3 IS
4 v_dias tab_dias := tab_dias ();
5
6 CURSOR c_dias IS
7 SELECT empno AS dias
8 FROM emp
9 WHERE deptno = par_deptno;
10 BEGIN
11 OPEN c_dias;
12
13 FETCH c_dias BULK COLLECT INTO v_dias;
14
15 CLOSE c_dias;
16
17 RETURN v_dias;
18 END;
19 /
Function created.
SQL> SELECT * FROM TABLE (f_dias (10));
COLUMN_VALUE
------------
7782
7839
7934
SQL>
So, basically, it works. There's something else that produces TOO_MANY_ROWS, not code you posted.

Implement a sequence that increments by value of a function

I am looking to create a simple sequence:
CREATE SEQUENCE supplier_seq
MINVALUE 1
START WITH 3
INCREMENT BY 4
CACHE 20000;
However, I want to semi-randomize the incrementing values with a function determined by some factors implemented on the java side.
I thought the first step for testing this might look something like this:
CREATE SEQUENCE supplier_seq
MINVALUE 1
START WITH 3
INCREMENT BY myfunction
CACHE 20000;
I tried this:
CREATE SEQUENCE supplier_seq
MINVALUE 1
START WITH 3
INCREMENT BY (declare
rtrnt number;
begin
rtrnt :=semiRandomize();
end;
)
CACHE 20000;
which I realize is ridiculous.. but there must be some way to do something like this. Any pointers?
How about this? Not really a sequence, but - might suit your needs. It is a function that selects a random number and stores it into a table with a primary key. If the number has already been used, it is skipped. The function checks whether all numbers have been used; if so, it raises an error.
In this example, I'm creating a 5-numbers "sequence" (so that it fails soon enough).
Table & function:
SQL> create table t_seq (supseq number constraint pk_tseq primary key);
Table created.
SQL> create or replace function f_supseq
2 return number
3 as
4 l_range number := 5; -- number of values in a "sequence"
5 l_seq number; -- a new "sequence" number
6 l_cnt number; -- number of used numbers
7 pragma autonomous_transaction;
8 begin
9 select count(*) into l_cnt from t_seq;
10 if l_cnt < l_range then
11 -- there are still some available numbers so - let's get them
12
13 -- don't let anyone mess with the table
14 lock table t_seq in exclusive mode;
15 while l_seq is null loop
16 begin
17 insert into t_seq (supseq) values
18 (round(dbms_random.value(1, l_range)))
19 returning supseq into l_seq;
20 exception
21 when dup_val_on_index then
22 -- that number has already been used; skip it
23 null;
24 end;
25 end loop;
26 commit;
27 else
28 raise_application_error(-20001, 'No more available numbers');
29 end if;
30
31 return l_seq;
32 end;
33 /
Function created.
Fetching random "sequence" values:
SQL> select f_supseq from dual;
F_SUPSEQ
----------
2
SQL> select f_supseq from dual;
F_SUPSEQ
----------
4
SQL> select f_supseq from dual;
F_SUPSEQ
----------
1
SQL> select f_supseq from dual;
F_SUPSEQ
----------
3
SQL> select f_supseq from dual;
F_SUPSEQ
----------
5
SQL> select f_supseq from dual;
select f_supseq from dual
*
ERROR at line 1:
ORA-20001: No more available numbers
ORA-06512: at "SCOTT.F_SUPSEQ", line 28
Table contents:
SQL> select * From t_seq;
SUPSEQ
----------
1
2
3
4
5
SQL>

How to execute 2 Store Procedures with conditions

I want to RUN SP2 inside SP1. The SP2 inserts several data into a table, one of those data is actual date.
So, i want that SP2 only execute if in the column date, the date is within the last 10 days.
It´s possible?
Thanks
Here's an example.
First, create a table and insert some sample rows:
SQL> create table my_tbl
2 (id number,
3 my_col date
4 );
Table created.
SQL> insert into my_tbl (id, my_col)
2 -- more than 10 days ago
3 select 1, date '2018-05-25' from dual union all
4 -- less than 10 days ago
5 select 2, date '2018-09-01' from dual;
2 rows created.
Create two procedures; SP_1 is supposed to call SP_2 if condition is met. I'm looping through both rows in the table; one row's date value is OK, another one isn't.
SQL> create or replace procedure sp_2 as
2 begin
3 dbms_output.put_line('...I am in SP_2 now');
4 end;
5 /
Procedure created.
SQL> create or replace procedure sp_1 as
2 begin
3 for cur_r in (select my_col from my_tbl order by id) loop
4 dbms_output.put_line('date value = ' || to_char(cur_r.my_col, 'yyyy-mm-dd'));
5 if cur_r.my_col >= trunc(sysdate) - 10 then
6 dbms_output.put_line('...calling SP_2');
7 sp_2;
8 else
9 dbms_output.put_line('...date condition failed - not calling SP_2');
10 end if;
11 end loop;
12 end;
13 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> begin
2 sp_1;
3 end;
4 /
date value = 2018-05-25
...date condition failed - not calling SP_2
date value = 2018-09-01
...calling SP_2
...I am in SP_2 now
PL/SQL procedure successfully completed.

Resources