UPDATE stored procedure with conditional arguments - oracle

I want to write an Oracle UPDATE stored procedure where I reset certain fields if BIT argument is true. If BIT argument is not true, then update should take the already existing value or skip updating the field. How can I achieve this?
What I am trying to achieve more or less is this
CREATE OR REPLACE PROCEDURE [dbo].[p_update_fields]
#ID varchar(255),
#RESET_FIELD_1 boolean,
#RESET_FIELD_2 boolean,
#RESET_FIELD_3 boolean
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
IF EXISTS (SELECT id FROM dbo.TABLE_NAME WHERE id = #ID)
declare field1_;
declare field2_;
select t.field1, t.field2 INTO field1_, field2_ FROM dbo.TABLE_NAME t where t.id = #ID
if(#RESET_FIELD_1 = true)
field1_ = null;
if(#RESET_FIELD_2 = true)
field2_ = null;
UPDATE dbo.TABLE_NAME
SET
field1 = field1_,
field2 = field2_
WHERE id = #ID
END TRANSACTION
SET NOCOUNT OFF;
END

If you do use Oracle, then have a look at the following example. I chose not to pass Boolean but numeric values (they are simpler to use; 1 represents "true", 0 is then "false").
Sample data:
SQL> SELECT * FROM table_name ORDER BY id;
ID FIELD1 FIELD2 FIELD3
---- ---------- ---------- ----------
A123 100 200 300
B456 1 2 3
Procedure:
SQL> CREATE OR REPLACE PROCEDURE p_update_fields (par_id IN VARCHAR2,
2 par_reset_1 IN NUMBER,
3 par_reset_2 IN NUMBER,
4 par_reset_3 IN NUMBER)
5 IS
6 BEGIN
7 UPDATE table_name
8 SET field1 = CASE WHEN par_reset_1 = 1 THEN NULL ELSE field1 END,
9 field2 = CASE WHEN par_reset_2 = 1 THEN NULL ELSE field2 END,
10 field3 = CASE WHEN par_reset_3 = 1 THEN NULL ELSE field3 END
11 WHERE id = par_id;
12 END;
13 /
Procedure created.
Testing: let's reset just FIELD1 for ID = 'A123':
SQL> BEGIN
2 p_update_fields (par_id => 'A123',
3 par_reset_1 => 1,
4 par_reset_2 => 0,
5 par_reset_3 => 0);
6 END;
7 /
PL/SQL procedure successfully completed.
Result:
SQL> SELECT * FROM table_name ORDER BY id;
ID FIELD1 FIELD2 FIELD3
---- ---------- ---------- ----------
A123 200 300 --> FIELD1 is now NULL
B456 1 2 3
SQL>

Related

Stored procedure with select count(*) and use count in IF statement

I am creating a stored procedure in Oracle database that's resulting in error "ORA-01858: a non-numeric character was found where a numeric was expected".
My procedure is as below:
create or replace procedure testProc(
id IN VARCHAR2,
user IN VARCHAR2,
sender IN VARCHAR2
)
as
vCount number;
begin
select count(*) into vCount from table1 where id='12345'
if vCount=0
insert into table1 (id, user, sender, status) values (id, user, partner, status);
else
update table1 set status='ERR' where id='12345'
end if;
end procedure;
Error: ORA-01858: a non-numeric character was found where a numeric was expected
I tried replacing vCount as int that did not help. Also tried declaring vCount below sender IN VARCHAR2.
Can someone please tell what is correct way to use the above procedure.
Use a MERGE statement then you can do it in a single statement (rather than SELECT followed by either INSERT or UPDATE):
CREATE PROCEDURE testProc(
i_id IN table1.id%TYPE,
i_user IN table1."USER"%TYPE,
i_sender IN table1.sender%TYPE,
i_status IN table1.status%TYPE
)
AS
BEGIN
MERGE INTO table1 dst
USING (
SELECT '12345' AS id
FROM DUAL
) src
ON (src.id = dst.id)
WHEN MATCHED THEN
UPDATE SET status = 'Err'
WHEN NOT MATCHED THEN
INSERT (id, "USER", sender, status)
VALUES (i_id, i_user, i_sender, i_status);
END testProc;
/
db<>fiddle here
This code can't possibly return error you specified because
procedure is invalid (mising statement terminators; column name can't be USER because it is a keyword, reserved for currently logged user)
that error code is related to date issues, while - in your code - there's nothing that looks like a date
Therefore, it is impossible to help you with error you stated. Otherwise, consider NOT naming procedure's parameters the same as column names because that leads to various problems.
Something like this would work, but it is not related to error you got.
Sample table:
SQL> CREATE TABLE table1
2 (
3 id VARCHAR2 (5),
4 c_user VARCHAR2 (20),
5 partner VARCHAR2 (10),
6 sender VARCHAR2 (10),
7 status VARCHAR2 (5)
8 );
Table created.
SQL>
Procedure:
SQL> CREATE OR REPLACE PROCEDURE testProc (p_id IN VARCHAR2,
2 p_user IN VARCHAR2,
3 p_sender IN VARCHAR2)
4 AS
5 vCount NUMBER;
6 BEGIN
7 SELECT COUNT (*)
8 INTO vCount
9 FROM table1
10 WHERE id = p_id;
11
12 IF vCount = 0
13 THEN
14 INSERT INTO table1 (id,
15 c_user,
16 sender,
17 status)
18 VALUES (p_id,
19 p_user,
20 NULL,
21 'NEW');
22 ELSE
23 UPDATE table1
24 SET status = 'ERR'
25 WHERE id = p_id;
26 END IF;
27 END testproc;
28 /
Procedure created.
Testing:
SQL> EXEC testproc('12345', 'Little', 'Foot');
PL/SQL procedure successfully completed.
SQL> SELECT * FROM table1;
ID C_USER PARTNER SENDER STATU
----- -------------------- ---------- ---------- -----
12345 Little NEW
SQL> EXEC testproc('12345', 'Little', 'Foot');
PL/SQL procedure successfully completed.
SQL> SELECT * FROM table1;
ID C_USER PARTNER SENDER STATU
----- -------------------- ---------- ---------- -----
12345 Little ERR
SQL>

Display the employee detail with department name of given Fname if he is accountant

input from
tblemp(empid number primary key,
fname varchar2(20),
lname varchar2(20),
jdate date, salary number,
mid number,
post varchar2(20),
did varchar2(10) references tbldept1 (did)) ;
tbldept1(did varchar2(10) primary key,dname varchar2(10));
Write a pl/sql block of code to Display the employee detail with department name of given Fname if he is accountant.
i am try it for two method but still i am get error .
first method in this code by using type function:
declare
type temp is record (
veid tblemp1.empid%type,
vfname tblemp1.fname%type,
vlname tblemp1.lname%type,
vsalary tblemp1.salary%type,
vmid tblemp1.mid%type,
vjdate tblemp1.jdate%type,
vpost tblemp1.post%type,
vdid tblemp1.did%type,
vdname tbldept.dname%type);
remp temp;
remp1 temp;
begin
select empid,fname,lname,salary,mid,jdate,post,d.did,dname into remp from tblemp1 e,tbldept d where e.did=d.did and empid=&empid;
select empid,fname,lname,salary,mid,jdate,post,d.did,dname into remp1 from tblemp1 e,tbldept d where e.did=d.did and e.post='Accountant';
dbms_output.put_line('empid = '||remp.empid);
dbms_output.put_line('fname = '||remp.fname);
dbms_output.put_line('lname = '||remp.lname);
dbms_output.put_line('jdate = '||remp.jdate);
dbms_output.put_line('mid = '||remp.mid);
dbms_output.put_line('post = '||remp.post);
dbms_output.put_line(' did = '||remp.did);
dbms_output.put_line(' salary = '||remp.salary);
dbms_output.put_line(' dname = '||remp1.dname);
end;
/
second method is by using row type function using
declare
remp tblemp1%rowtype;
remp1 tbldept%rowtype;
begin
select * into remp from tblemp1 where empid=&empid and post='Accountant';
select * into remp1 from tbldept ;
dbms_output.put_line('empid = '||remp.empid);
dbms_output.put_line('fname = '||remp.fname);
dbms_output.put_line('lname = '||remp.lname);
dbms_output.put_line('jdate = '||remp.jdate);
dbms_output.put_line('mid = '||remp.mid);
dbms_output.put_line('post = '||remp.post);
dbms_output.put_line(' did = '||remp.did);
dbms_output.put_line(' salary = '||remp.salary);
dbms_output.put_line(' dname = '||remp1.dname);
end;
/
i am try it with two method .
im try it till morning but untill i am not getting output.
my prectical exam pass come so plaese help me.
I wasn't sure if your table names were correct (your code didn't match your question text), but if you fix them, then your code looks reasonable to me
SQL> create table tbldept1(did varchar2(10) primary key,dname varchar2(10));
Table created.
SQL>
SQL> create table tblemp(empid number primary key, fname varchar2(20), lname varchar2(20),
2 jdate date, salary number, mid number, post varchar2(20), did varchar2(10) references tbldept1 (did)) ;
Table created.
SQL>
SQL> insert into tbldept1 values (10,'Accounts');
1 row created.
SQL> insert into tblemp values (1000,'Jane','Doe',sysdate,1000,1001,'Accountant',10);
1 row created.
SQL>
SQL>
SQL> set serverout on
SQL> declare
2 remp tblemp%rowtype;
3 remp1 tbldept1%rowtype;
4
5 begin
6 select * into remp from tblemp where empid=&empid and post='Accountant';
7
8 select * into remp1 from tbldept1 ;
9
10 dbms_output.put_line('empid = '||remp.empid);
11 dbms_output.put_line('fname = '||remp.fname);
12 dbms_output.put_line('lname = '||remp.lname);
13 dbms_output.put_line('jdate = '||remp.jdate);
14 dbms_output.put_line('mid = '||remp.mid);
15 dbms_output.put_line('post = '||remp.post);
16 dbms_output.put_line(' did = '||remp.did);
17 dbms_output.put_line(' salary = '||remp.salary);
18 dbms_output.put_line(' dname = '||remp1.dname);
19
20 end;
21 /
Enter value for empid: 1000
old 6: select * into remp from tblemp where empid=&empid and post='Accountant';
new 6: select * into remp from tblemp where empid=1000 and post='Accountant';
empid = 1000
fname = Jane
lname = Doe
jdate = 22-MAR-22
mid = 1001
post = Accountant
did = 10
salary = 1000
dname = Accounts
PL/SQL procedure successfully completed.

Oracle PL/SQL: Return true if column has at least "one null value" or "no data found"

How to return TRUE if column has at least one value as null OR no data found for any foreign key column value?
Tried searching for answers on the internet and could not find any with this combination. Hence posting it here.
Below is the data: Table name - MY_EMP
+----+------------+-----------+---------------------------+--------+
| id | first_name | last_name | email | fk_col |
+----+------------+-----------+---------------------------+--------+
| 1 | Hurleigh | Stove | | 1 |
| 2 | Joline | | | 1 |
| 3 | Martynne | Honatsch | mhonatsch2#infoseek.co.jp | 2 |
| 4 | Willyt | Fullylove | wfullylove3#hhs.gov | 2 |
| 5 | Joelly | | jferriday4#twitpic.com | 3 |
+----+------------+-----------+---------------------------+--------+
If last_name is null OR email is null for any fk_col then return true
If last_name is null OR email is null for invalid fk_col then return true
else return False
Tried to write function and was testing code. Here's the code which goes into function:
DECLARE
v_verify NUMBER(2);
BEGIN
SELECT DISTINCT 1
INTO v_verify
FROM my_emp
WHERE ( last_name IS NULL
OR email IS NULL )
AND fk_col = :custom_fk;
dbms_output.Put_line('Return True');
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line('Return False');
END;
When parameter :custom_fk = 1 then value returns TRUE (That is correct)
When parameter :custom_fk = 2 then value returns FALSE (That is correct)
When parameter :custom_fk = 700 then value returns FALSE (Incorrect as per my requirement) -- Here I want value to return true and unable to figure it out how to tweak code to match to my requirement.
Hope I get some help here.
Below is the code to create table and insert data:
/* CREATE TABLE */
CREATE TABLE MY_EMP(
id NUMBER(5) NOT NULL,
first_name VARCHAR2(100) NOT NULL,
last_name VARCHAR2(100),
email VARCHAR2(100),
fk_col NUMBER(5),
CONSTRAINT "MY_EMP_PK" PRIMARY KEY ("ID")
);
/*Insert data*/
INSERT INTO my_emp(id, first_name, last_name, email, fk_col)
VALUES(1, 'Hurleigh', 'Stove', '', 1);
INSERT INTO my_emp(id, first_name, last_name, email, fk_col)
VALUES(2, 'Joline', '', '', 1);
INSERT INTO my_emp(id, first_name, last_name, email, fk_col)
VALUES(3, 'Martynne', 'Honatsch', 'mhonatsch2#infoseek.co.jp', 2);
INSERT INTO my_emp(id, first_name, last_name, email, fk_col)
VALUES(4, 'Willyt', 'Fullylove', 'wfullylove3#hhs.gov', 2);
INSERT INTO my_emp(id, first_name, last_name, email, fk_col)
VALUES(5, 'Joelly', '', 'jferriday4#twitpic.com', 3);
Thanks,
Richa
Would this do?
SQL> with temp as
2 (select count(*) cnt
3 from (select distinct 1 as val
4 from my_emp
5 where fk_col = &&par_fk_col
6 and ( last_name is null
7 or email is null
8 )
9 union all
10 select distinct 2
11 from my_emp
12 where fk_col = &&par_fk_col
13 )
14 )
15 select case when cnt = 1 then 'false'
16 else 'true'
17 end as result
18 from temp;
It results in
Enter value for par_fk_col: 1
RESUL
-----
true
SQL> undefine par_fk_col
SQL> /
Enter value for par_fk_col: 2
RESUL
-----
false
SQL> undefine par_fk_col
SQL> /
Enter value for par_fk_col: 3
RESUL
-----
true
SQL> undefine par_fk_col
SQL> /
Enter value for par_fk_col: 700
RESUL
-----
true
SQL>
That's all in one select statement. If you're writing a function, it is probably simpler to check whether fk_col exists in a separate query; if not, return true immediately. If so, then check for other conditions.
(BTW, thank you for test case. It is SO rare that I'm positively surprised!)
[EDIT] To "convert" that statement into PL/SQL isn't that difficult. Instead of an anonymous PL/SQL block, I'd suggest a function.
SQL> create or replace function f_test (par_fk_col in my_emp.fk_col%type)
2 return varchar2
3 is
4 retval varchar2(10);
5 begin
6 with temp as
7 (select count(*) cnt
8 from (select distinct 1 as val
9 from my_emp
10 where fk_col = par_fk_col
11 and ( last_name is null
12 or email is null
13 )
14 union all
15 select distinct 2
16 from my_emp
17 where fk_col = par_fk_col
18 )
19 )
20 select case when cnt = 1 then 'false'
21 else 'true'
22 end
23 into retval
24 from temp;
25
26 return retval;
27 end;
28 /
Function created.
Testing:
SQL> select f_test(1) from dual;
F_TEST(1)
---------------------------------------
true
SQL> select f_test(2) from dual;
F_TEST(2)
---------------------------------------
false
SQL> select f_test(700) from dual;
F_TEST(700)
---------------------------------------
true
SQL>
SELECT case when count(*)=1 then 'true' else 'false' end ret_value
from dual
where not exists(
SELECT null
FROM my_emp
WHERE fk_col = :custom_fk
having count(*)>0
and count(*)=count(last_name)
and count(*)=count(email)
);
Example:
SQL> ho cat tests/2.sql
SELECT case when count(*)=1 then 'true' else 'false' end ret_value
from dual
where not exists(
SELECT null
FROM my_emp
WHERE fk_col = &1
having count(*)>0
and count(*)=count(last_name)
and count(*)=count(email)
);
SQL> #tests/2.sql 1
RET_V
-----
true
SQL> #tests/2.sql 2
RET_V
-----
false
SQL> #tests/2.sql 3
RET_V
-----
true
SQL> #tests/2.sql 700
RET_V
-----
true

Create Trigger in Oracle, in order to check two Dates

I would like to create a Trigger in Oracle, in order to check the Current Date with the Date that is stored in a specific column and if they are equal, I would like to change a boolean value on the same table. I am new to Oracle and especially on creating triggers. Any help is much appreciated.
CREATE TABLE DISCIPLINARYAUDIT
(
DISCIPLINARYAUDITID NUMBER(19, 0) NOT NULL
, DISCIPLINARYAUDITTYPE VARCHAR2(255 CHAR) NOT NULL
, REVOCATIONORCOMPLETION NUMBER(1, 0)
, STARTDATE DATE
, ENDDATE DATE
)
When endDate equals with current Date, RevocationORCompletion must chenage from 0 to 1.
Thank you in advance.
Here's an example.
Date format and today's date:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
Sample table:
SQL> create table test (id number, specific_column date, boolean_column varchar2(10));
Table created.
SQL> insert into test values (1, trunc(sysdate), 'FALSE');
1 row created.
SQL> insert into test values (2, trunc(sysdate) - 2, 'FALSE');
1 row created.
SQL> select * from test order by id;
ID SPECIFIC_C BOOLEAN_CO
---------- ---------- ----------
1 04.06.2020 FALSE
2 02.06.2020 FALSE
Trigger:
SQL> create or replace trigger trg_biu_test
2 before insert or update on test
3 for each row
4 begin
5 if :new.specific_column = trunc(sysdate) then
6 :new.boolean_column := 'TRUE';
7 end if;
8 end;
9 /
Trigger created.
Testing:
SQL> update test set id = 3 where id = 1;
1 row updated.
SQL> update test set id = 5 where id = 2;
1 row updated.
SQL> select * from test;
ID SPECIFIC_C BOOLEAN_CO
---------- ---------- ----------
3 04.06.2020 TRUE
5 02.06.2020 FALSE
SQL>

Oracle SQL%ROWCOUNT statement always return 1

I have a simple table USERS in Oracle with 2 columns ID and USERNAME.
ID is the primary key and auto incremented using a trigger.
I am inserting or updating records using a procedure like this
CREATE OR REPLACE PROCEDURE SaveUser(UID NUMBER, UN VARCHAR2, Row_Count OUT NUMBER) IS
BEGIN
IF(UID > 0) THEN
UPDATE USERS SET USERNAME = UN WHERE ID = UID;
ELSE
INSERT INTO USERS(USERNAME) VALUES(UN);
END IF;
Row_Count := SQL%ROWCOUNT;
END;
I am calling the procedure like this:
VARIABLE Row_Count NUMBER;
EXEC SaveUser(50, 'Username_1', Row_Count);
PRINT Row_Count;
The issue is I am passing 50 as the first parameter, but in the table there is no row with ID 50. But I am getting 1 as the result. Even if the row is not updated, SQL%ROWCOUNT statement returns 1. Can anyone help me to fix this?
The above code is simplified one and the exact code is here
CREATE OR REPLACE PROCEDURE SaveEmployee(ID NUMBER, User_Name VARCHAR2, Emp_Password VARCHAR2, Emp_Full_Name VARCHAR2, Emp_Date_Of_Birth DATE, Emp_Gender_ID NUMBER, Emp_Work_Type_ID NUMBER, Emp_Salary FLOAT, Emp_Email VARCHAR2, Row_Count OUT NUMBER) IS
Username_Row_Count NUMBER := 0;
Email_Row_Count NUMBER := 0;
BEGIN
IF(ID > 0) THEN
SELECT COUNT(1) INTO Username_Row_Count FROM EMPLOYEES WHERE LOWER(USERNAME) = LOWER(User_Name) AND EMPLOYEE_ID <> ID;
SELECT COUNT(1) INTO Email_Row_Count FROM EMPLOYEES WHERE LOWER(EMAIL) = LOWER(Emp_Email) AND EMPLOYEE_ID <> ID;
IF(Username_Row_Count = 0 AND Email_Row_Count = 0) THEN
UPDATE EMPLOYEES
SET USERNAME = LOWER(User_Name), PASSWORD = Emp_Password, FULL_NAME = Emp_Full_Name, DATE_OF_BIRTH = Emp_Date_Of_Birth, GENDER_ID = Emp_Gender_ID, WORK_TYPE_ID = Emp_Work_Type_ID, SALARY = Emp_Salary, EMAIL = LOWER(Emp_Email)
WHERE EMPLOYEE_ID = ID;
END IF;
ELSE
SELECT COUNT(1) INTO Username_Row_Count FROM EMPLOYEES WHERE LOWER(USERNAME) = LOWER(User_Name);
SELECT COUNT(1) INTO Email_Row_Count FROM EMPLOYEES WHERE LOWER(EMAIL) = LOWER(Emp_Email);
IF(Username_Row_Count = 0 AND Email_Row_Count = 0) THEN
INSERT INTO EMPLOYEES(USERNAME, PASSWORD, FULL_NAME, DATE_OF_BIRTH, GENDER_ID, WORK_TYPE_ID, SALARY, EMAIL, LOGIN_ATTEMPTS)
VALUES(LOWER(User_Name), Emp_Password, Emp_Full_Name, Emp_Date_Of_Birth, Emp_Gender_ID, Emp_Work_Type_ID, Emp_Salary, LOWER(Emp_Email), 0);
END IF;
END IF;
Row_Count := SQL%ROWCOUNT;
END;
I can't reproduce what you are saying:
SQL> select * from users;
no rows selected
SQL> declare
2 uid number := 50;
3 begin
4 if uid > 0 then
5 update users set username = '&&un' where id = uid;
6 else
7 insert into users (username) values ('&&un');
8 end if;
9 dbms_output.put_line(sql%rowcount);
10 end;
11 /
Enter value for un: 50
0 --> this is SQL%ROWCOUNT
PL/SQL procedure successfully completed.
SQL>
Code you posted is invalid (there's no NUBER datatype). It would help if you posted something that actually works, because - the way you put it - we can't be sure that what you claim to be true really is true. Please, copy/paste your own SQL*Plus session (just like I did) so that we'd see what you really have and how Oracle responded.
Add SQL%ROWCOUNT after the update to get the update count
UPDATE EMPLOYEES
SET USERNAME = LOWER(User_Name), PASSWORD = Emp_Password, FULL_NAME = Emp_Full_Name, DATE_OF_BIRTH = Emp_Date_Of_Birth, GENDER_ID = Emp_Gender_ID, WORK_TYPE_ID = Emp_Work_Type_ID, SALARY = Emp_Salary, EMAIL = LOWER(Emp_Email)
WHERE EMPLOYEE_ID = ID;
Row_Count := SQL%ROWCOUNT;
Now it's more clear.
This code:
SELECT COUNT(1) INTO Username_Row_Count FROM EMPLOYEES WHERE LOWER(USERNAME) = LOWER(User_Name) AND EMPLOYEE_ID <> ID;
SELECT COUNT(1) INTO Email_Row_Count FROM EMPLOYEES WHERE LOWER(EMAIL) = LOWER(Emp_Email) AND EMPLOYEE_ID <> ID;
must update the values Username_Row_Count and Email_Row_Count, so that the condition
IF(Username_Row_Count = 0 AND Email_Row_Count = 0) THEN
is always false. And the update is never executed. As the result, in your Row_Count variable you get the result of the last select, which is 1 row.

Resources