insert statement in oracle without using user defined function - sql

I have table employees with columns eno, ename, job, sal, comm
and the query like
INSERT a new employee
eno as 7787,
ename as 'abc',
job as 'salesman'
sal as 2000,
comm as tax amount
this tax is the function like
CREATE OR REPLACE FUNCTION tax
( p_sal employees.sal%type
)
RETURN NUMBER
IS
v_tax employees.sal%type;
BEGIN
v_tax:= CASE
WHEN SAL> 4000 THEN SAL * 0.33
WHEN SAL >2500 THEN SAL *0.25
WHEN SAL >1500 THEN SAL * 0.20
ELSE 0
END;
RETURN v_tax
END tax;
At the INSERT statement I can't use function tax for the column comm.
Is there any other method to do this, or how can this be best achieved?

When you say
I can't use function tax for the column comm
do you mean you're not allowed to use this function, or you can't figure out how to use it?
Assuming the latter, I don't see why you shouldn't be able to use a function in an INSERT statement. You have, however, got the syntax of the INSERT statement completely wrong.
Try
INSERT INTO employee (eno, ename, job, sal, comm)
VALUES (7787, 'abc', 'salesman', 2000, tax(2000));
I don't know where amount in your INSERT statement comes from, but given that your function takes a parameter called p_sal, I'm guessing it's applied to the value in the column sal.

Related

there is few mistake in trigger help me to solve that problem

Create trigger that will
not allow update of salary for employee
who are in sales department.
Emp(no,name,dno,salary,designamtion)
Dept(dno,name,location)
Errors: TRIGGER MYTRIGGER1
Line/Col: 6/11 PLS-00049: bad bind variable 'OLD.EMP'
Line/Col: 6/31 PLS-00049: bad bind variable 'OLD.EMP'
DROP TABLE EMP;
DROP TABLE DEPT;
CREATE TABLE Dept
(
dno NUMBER PRIMARY KEY,
name VARCHAR(15),
location VARCHAR(15) );
CREATE TABLE Emp
(
no NUMBER PRIMARY KEY,
name VARCHAR(15),
dno NUMBER,
salary NUMBER,
designamtion VARCHAR(15),
FOREIGN KEY(dno) REFERENCES Dept(dno) );
insert into DEPT values (1,'SALES','GUJARAT');
insert into DEPT values (2,'MARKETING','UP');
insert into DEPT values (3,'MANUFACTURING','MP');
insert into DEPT values (4,'DEALING','VAPI');
insert into DEPT values (5,'SELL','TAPI');
insert into EMP values (1,'AMAN',2,45400,'MANAGER');
insert into EMP values (2,'BHAMAN',5,20000,'GM');
insert into EMP values (3,'CHAMAN',3,34400,'ADVISOR');
insert into EMP values (4,'DAMAN',4,75400,'WORKER');
insert into EMP values (5,'KHAMAN',1,42400,'MANAGER');
CREATE OR REPLACE trigger MYTRIGGER1
BEFORE UPDATE OF SALARY ON EMP
for each row
declare
hmmm VARCHAR(15);
begin
select Dept.name into hmmm
from Dept, Emp
where :old.emp.no=no and :old.emp.dno=Dept.dno;
dbms_output.put_line(hmmm);
end;
You don't need to alias the table the trigger is on. This will compile fine:
CREATE OR REPLACE trigger MYTRIGGER1
BEFORE UPDATE OF SALARY ON EMP
for each row
declare
hmmm VARCHAR(15);
begin
select Dept.name into hmmm
from Dept, Emp
where :old.no=no and :old.dno=Dept.dno;
dbms_output.put_line(hmmm);
end;
However, this trigger will fail when you update the table. You cannot select from the table itself in the trigger body. This will raise a mutating table error. Since it is an assignment I'll leave the research up to you.
As Koen said, your code will suffer from mutating table error.
Lucky you - you don't have to select from the table you're just updating (the emp table, right?) - you have everything you need in :new.dno. So:
SQL> create or replace trigger mytrigger1
2 before update of salary on emp
3 for each row
4 declare
5 hmmm varchar2(15);
6 begin
7 select d.name
8 into hmmm
9 from dept d
10 where d.dno = :new.dno;
11
12 dbms_output.put_line('Department name = ' || hmmm);
13 end;
14 /
Trigger created.
Testing:
SQL> set serveroutput on
SQL>
SQL> update emp set salary = 1000 where no = 1;
Department name = MARKETING
1 row updated.
SQL> update emp set salary = 1000;
Department name = MARKETING
Department name = SELL
Department name = MANUFACTURING
Department name = DEALING
Department name = SALES
5 rows updated.
SQL>
Your request is a trigger that disallows certain action for employees in Sales. Your trigger would not do so even it compiled. Two problems:
dbms_output does not prevent anything it merely 'prints' a message.
it prevents any update to salary, except when emp.dno or emp.no is also updated.
First (getting up on soapbox). You are enforcing a business rule. This should not be done in a trigger. It should be done in either the business rules engine of your application or in a database constraint or if you want to be super cautions both. Now a trigger will do the enforcement but business rule violations should glaringly obvious and easy to find, in a trigger becomes a side effect of an action, hidden away and difficult to find. (OK enough of that getting off soapbox).
The prevention method your looking for is raise_application_error. And you want a little code as possible in a trigger. In this case you have everything needed from the EMP table through the pesudo rows :old and :new so there is no reason to join your tables. However you do need to look at the specific department. It is too bad Oracle constrains the Exists predicate to introduction of a sub-select, this would be a perfect place for the structure:
If EXISTS (selects ...) then ...
But that is not available. The following uses a technique of reversing the requirement. That is it selects what is NOT wanted then if found it raise the exception, and if not found it suppress the Oracle raised error. So:
create or replace trigger mytrigger1
before update of salary on emp
for each row
declare
hmmm varchar2(01);
begin
select null
into hmmm
from dept d
where d.dno = :old.dno
and d.name = 'SALES';
raise_application_error(-20199, 'Can not update salary for Employee in Sales.');
exception
when no_data_found then null;
end mytrigger1;
This is sometimes referred to as "Programming the Exception" and is not a generally recommended procedure but at times it is useful. See fiddle here.
There is an outstanding question not addressed here. Can an employee in Sales have a salary change if they are also transferring departments. I.e. should the following succeed or fail?
update emp e
set dno = 2
, salary = salary + 5000
where e.no = 5;

PLSQL block to increase salary of departments

I have to Increase the Salary of employees working in deptno 10 by 15%, Deptno 20 by 15% and others by 5% and display the corresponding the employees working in that Dept. I am able to increase the salary of departmnet 10 and 20 but I am not able to increase the salary of other departments by 5%. I have tried with for loop too.This is a practice question.
My question is this:(Display the all records from the Dept table. Increase the Salary of employees working in deptno 10 by 15%, Deptno 20 by 15% and others by 5% Also display the corresponding the employees working in that Dept. Use a parameter Cursor and Cursor with Update clause.)
MY code:
declare
cursor sal_increase(v_dno number) is select empno,sal,ename,deptno from emp where deptno=v_dno ;
emp_record sal_increase%rowtype;
begin
OPEN sal_increase(10);
LOOP
FETCH sal_increase INTO emp_record;
EXIT WHEN sal_increase%NOTFOUND;
update emp set sal=sal+sal*0.15 where empno=emp_record.empno;
DBMS_OUTPUT.PUT_LINE(emp_record.ename||' '||emp_record.deptno);
END LOOP;
CLOSE sal_increase;
OPEN sal_increase(20);
LOOP
FETCH sal_increase INTO emp_record;
EXIT WHEN sal_increase%NOTFOUND;
update emp set sal=sal+sal*0.15 where empno=emp_record.empno;
DBMS_OUTPUT.PUT_LINE(emp_record.ename||' '||emp_record.deptno);
END LOOP;
CLOSE sal_increase;
end;
You don't need any procedural code at all to do this. That would just unnecessarily and severely slow it down, especially the use of cursors.
Instead just use a simple UPDATE with a CASE expression returning the new salary depending on the department.
UPDATE emp
SET sal = CASE
WHEN deptno IN (10, 20) THEN
sal * 0.15
ELSE
sal * 0.05
END;
For the output just use a SELECT.
SELECT ename || ' ' || deptno
FROM emp;
Don't forget the solution from #sticky bit for future.
Going back to your requirement , I believe you stick to do it with one anonymous block and with parameterized cursor.(correct me if I am wrong)
if yes, I would change the following and it should do the work for you.
Change your cursor to below, For others you pass null as parameter and in the where clause we can handle the same. (when value pass as 10 or 20 it will do a comparison and when null it will update for all other than 10 and 20)
CURSOR sal_increase(v_dno NUMBER) IS
SELECT empno
,sal
,ename
,deptno
FROM emp
WHERE ( v_dno IS NOT NULL AND deptno = v_dno
OR v_dno IS NULL AND deptno NOT IN (10,20)
);
Then call again the cusrosr as you did for 10 and 20 once more like below,
OPEN sal_increase(v_dno => NULL);
LOOP
FETCH sal_increase
INTO emp_record;
EXIT WHEN sal_increase%NOTFOUND;
UPDATE emp SET sal = sal * 0.05 WHERE empno = emp_record.empno;
dbms_output.put_line(emp_record.ename || ' ' || emp_record.deptno);
END LOOP;
CLOSE sal_increase;

How to format currency in Oracle SQL Developer 19.4.0?

I'm using SQL developer in one of my database classes and I have homework where certain formatting is needed. When I use the commands given by the professor on my SQL Developer I get an error
Here are the commands:
col price format $99,990.99
col quoted_price format $99,990.99
col balance format $99,990.99
col credit_limit format 99,990.99
The errors I get are:
SP2-0246: Illegal FORMAT string "$99,"
SP2-0246: Illegal FORMAT string "$99,"
SP2-0246: Illegal FORMAT string "$99,"
SP2-0246: Illegal FORMAT string "99,"
When I run these same commands on the lab computer it works but the lab uses an outdated version of SQL developer. It's version 4.1.1
Would appreciate any help
The homework is asks us to input a command that would display query results for example a question would be "x" situation
My command will be:
SELECT item_num, price, description, balance
from item;
The query output below will have $ if needed and will have the commas and periods.
If you are storing salary as Number, then you can use to_char(column,'$9,999.99');
SQL> CREATE TABLE EMP
2 (EMPNO NUMBER(4) NOT NULL,
3 ENAME VARCHAR2(10),
4 JOB VARCHAR2(9),
5 MGR NUMBER(4),
6 HIREDATE DATE,
7 SAL NUMBER(7, 2),
8 COMM NUMBER(7, 2),
9 DEPTNO NUMBER(2)
10 );
SQL> INSERT INTO EMP VALUES (7369, 'SMITH', 'CLERK', 7902,TO_DATE('17-DEC-1980', 'DD-MON-YYYY'), 800, NULL, 20);
SQL> select ename, to_char( sal, '$9,999.99' ) "Salary" from emp;
ENAME Salary
---------- ----------
SMITH $800.00

How to make :NEW dynamic PL/SQL

This is my trigger code. But I want to dynamically reference :new attributes without writing them one by one. How can I do that?
create or replace TRIGGER test_CHANGE_TRIGGER
AFTER INSERT OR UPDATE OR DELETE
ON test
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO test_LOG
VALUES (:NEW.d, :NEW.s, :NEW.n, :NEW.v, :NEW.e, SYSDATE, USER, 'I');
END IF;
END;
You could write a sql statement to generate the insert statement for you. Copy the result and paste it in the trigger code.
Example for table emp:
SELECT
'INSERT INTO emp_log(empno,ename, job, mgr, hiredate, sal, comm, deptno, log_date, user, operation) VALUES ('||
':NEW.'||LISTAGG(column_name,' ,:NEW.') WITHIN GROUP(order by column_id)||',SYSDATE,USER,''I'')'
FROM user_tab_columns
WHERE table_name = 'EMP';
This will return
INSERT INTO emp_log(empno,ename, job, mgr, hiredate, sal, comm, deptno, log_date, user, operation) VALUES (:NEW.EMPNO ,:NEW.ENAME ,:NEW.JOB ,:NEW.MGR ,:NEW.HIREDATE ,:NEW.SAL ,:NEW.COMM ,:NEW.DEPTNO,SYSDATE,USER,'I')
Lucky you, the answer is pretty straightforward: you can't do that, and you have to name all values one-by-one.
Unfortunately, there's nothing (provided by Oracle) you could use for that purpose.
Though, you could try to create your own procedure which would use dynamic SQL and create triggers for you (query user_tab_columns to get list of all columns). Dynamic SQL doesn't scale well, is difficult to debug, but - if you think that it'll help (because there are hundreds of triggers you have to create) - go for it.

Insert value with substitution variable

How can i use substitution variable in loop for inserting value in the below statement... loop limit is 5 times :
insert into emp
(eid, ename, salary, hire_date, address)
values
(&eid, '&ename', &salary, '&hire_date', '&address');