Learning SQL in Free Time - sql

So i have the following table
EMPNO ENAME DEPTN JOB HIREDDATE SALARY
111 Narayan R22 Electrical 26-DEC-99 5000
108 Horen P69 PWD 10-DEC-95 10000
130 Roy A13 Security 15-SEP-01 25000
420 Roy D12 IT 15-SEP-99 2500
100 Allu A13 Security 26-JAN-15 15000
With datatypes
EMPNO NOT NULL NUMBER(38),
ENAME NOT NULL VARCHAR2(20),
DEPTNO VARCHAR2(5),
JOB VARCHAR2(20),
HIREDDATE DATE,
SALARY NUMBER(38)
I want to try to create a stored procedure
a) Changing the hire date of any employee.
b) Performing DML commands (Insert, Update and Delete)
c) Multiplying two numbers
I tried to use this code
CREATE PROCEDURE ChangeHired #EmpNo int, #Hired date
AS
ALTER TABLE Employee01 MODIFY HireDate = #Hired WHERE EmpNo = #EmpNo
GO;
But it doesn't work in Oracle 10g. Need some help.
Edit: UPDATE Employee01 SET HireDate = #Hired WHERE EmpNo = #EmpNo should be used that was a mistake from my side but still the code is not executed.

Please use below query,
update Employee01 set HireDate = #Hired WHERE EmpNo = #EmpNo
You have just created the procedure, to make it work you have to call it, Call the procedure using,
execute procedure_name(parameter1, parameter2);
Alter statement should be used only when modifying your structure of the table. While working with data, please use only DML's.

Syntax you used (or Jim suggested) isn't Oracle. Should be something like this (including that "multiplying" example you asked for):
Sample data (only minimum columns needed for the procedure to work):
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> select * From employee1;
EMPNO HIREDDATE
---------- ----------
111 08.06.2020
Procedure:
SQL> create or replace procedure changehired(par_empno in int, par_hired in date)
2 is
3 a number := 2;
4 b number := 3;
5 result number;
6 begin
7 update employee1 set
8 hireddate = par_hired
9 where empno = par_empno;
10
11 result := a * b;
12 dbms_output.put_line(a || ' * '|| b || ' = ' || result);
13 end;
14 /
Procedure created.
Testing: once the procedure is created, you have to execute it. In order to see result of dbms_output.put_line, enable serveroutput in tool you use (for SQL*Plus or SQL Developer, execute set serveroutput on).
SQL> set serveroutput on;
SQL> begin
2 changehired(111, date '2020-06-08');
3 end;
4 /
2 * 3 = 6
PL/SQL procedure successfully completed.
SQL> select * from employee1;
EMPNO HIREDDATE
---------- ----------
111 08.06.2020
SQL>

Related

Oracle trigger multiple conditions in when clause

I'm trying to create a trigger that updates a column in a table when other columns are updated. but getting the following error while saving the trigger
ORA-25000: invalid use of bind variable in trigger WHEN clause
My trigger is as follows, I'm not sure what is wrong with the code.
CREATE OR REPLACE TRIGGER Employees_ARIU
BEFORE INSERT OR UPDATE ON Employees
FOR EACH ROW
WHEN ((nvl(:OLD.EMP_SAL,0) != nvl(:NEW.EMP_SAL,0)) OR (nvl(:OLD.SAL_LEVEL,0) != nvl(:NEW.SAL_LEVEL,0)))
BEGIN
:NEW.LAST_UPDATED = SYSDATE
END;
Although IF is an alternative to WHEN, I'd say that it is better to use WHEN clause whenever possible because it is a
SQL condition that must be satisfied for the database to fire the trigger
So, why would you even let the trigger fire and then conclude that oh, OK, I don't want to do anything, after all? Better not running it at all!
Yes, WHEN clause has its restrictions and you can't put anything you want in there, but - your case isn't one of those.
(more info in Documentation, search for "WHEN clause").
So, for a sample table
SQL> create table employees
2 (id number,
3 emp_sal number,
4 sal_level number,
5 last_updated date);
Table created.
trigger would looks like this:
SQL> create or replace trigger employees_ariu
2 before insert or update on employees
3 for each row
4 when ( nvl(old.emp_sal, 0) <> nvl(new.emp_sal, 0)
5 or nvl(old.sal_level, 0) <> nvl(new.sal_level, 0)
6 )
7 begin
8 :new.last_updated := sysdate;
9 end;
10 /
Trigger created.
Testing:
SQL> insert into employees (id, emp_sal, sal_level) values (1, 100, 1);
1 row created.
SQL> select * from employees;
ID EMP_SAL SAL_LEVEL LAST_UPDATED
---------- ---------- ---------- -------------------
1 100 1 12.06.2021 12:14:17
SQL> update employees set sal_level = 2 where id = 1;
1 row updated.
SQL> select * from employees;
ID EMP_SAL SAL_LEVEL LAST_UPDATED
---------- ---------- ---------- -------------------
1 100 2 12.06.2021 12:14:33
SQL>
I think you can try updating your WHEN condition to IF statement along with few other changes -
CREATE OR REPLACE TRIGGER Employees_ARIU
BEFORE INSERT OR UPDATE ON Employees
FOR EACH ROW
BEGIN
IF ((nvl(:OLD.EMP_SAL,0) != nvl(:NEW.EMP_SAL,0)) OR (nvl(:OLD.SAL_LEVEL,0) != nvl(:NEW.SAL_LEVEL,0))) then
:NEW.LAST_UPDATED := SYSDATE;
END IF;
END;
/
Here is the fiddle.

Oracle SQL Developer dynamic date table name

I'm hoping to dynamically reference last Fridays date in the weekly sales tables in Oracle SQL Developer i.e. SELECT * FROM Sales_DDMMYY
I can do this in SQL Server (DECLARE / SET / EXECUTE) but haven't had any joy with SQL Developer.
Even the ability to create a date variable to be referenced within the code would be a great start.
Stop!
I strongly suggest you not to do that. That's not the way to create a data model. If you have a table which contains values related to different dates, then date should be a column in that table, such as
create table sales
(id number,
datum date,
amount number
);
Insert rows as
insert into sales (id, datum, amount)
select 1, date '2020-06-01', 100 from dual union all
select 2, date '2020-05-13', 240 from dual union all
select 3, date '2020-05-13', 160 from dual;
and use it as
select sum(amount)
from sales
where datum = date '2020-05-13'
That is the way to do it. Naming columns by dates is ... well, close to a suicide.
Aha, now I see: it is a table name that contains dates. Doesn't really matter, my suggestion still stands. Do not do that. Use a date column within a single table.
If you want - and if you can afford it - partition the table on date value. Note that partitioning option exists in Oracle Enterprise Edition which is quite expensive. So - date column it is.
If there's nothing you can do about it, then dynamic SQL it is. For example:
Sample table:
SQL> create table sales_200620 as select * From dept;
Table created.
Function that accepts ddmmyy value as a parameter, composes table name and returns a refcursor:
SQL> create or replace function f_test (par_ddmmyy in varchar2)
2 return sys_refcursor
3 is
4 l_table_name varchar2(30) := 'sales_' || par_ddmmyy;
5 l_rc sys_refcursor;
6 begin
7 open l_rc for 'select * from ' || dbms_assert.sql_object_name(l_table_name);
8 return l_rc;
9 end;
10 /
Function created.
Testing:
SQL> select f_test('200620') from dual;
F_TEST('200620')
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
Without creating a function: use substitution variable:
SQL> select * From &tn;
Enter value for tn: sales_200620
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>

trigger in PL/SQL

There are two tables given:
1)
employee(eno,ename,basic,da,gross)
da=basic*(5.0/100)
gross = basic+da
2)
sal_hist(eno, sys_dt, old_basic)
How to write a trigger to update the 'da' and 'gross' whenever I am updating basic salary of the employee?
PL/SQL tag suggests that you use Oracle database.
You said that there's yet another table, sal_hist, but - you didn't say what to do with it. I presume you'd want to save the old basic salary.
In that case, trigger would look like this:
SQL> create or replace trigger trg_biu_emp
2 before insert or update on employee
3 for each row
4 begin
5 insert into sal_hist(eno, sys_dt, old_basic) values
6 (:new.eno, sysdate, :old.basic);
7
8 :new.da := :new.basic * 5 / 100;
9 :new.gross := :new.basic + :new.da;
10 end;
11 /
Trigger created.
Let's see how it works:
SQL> select * From employee;
ENO ENAME BASIC DA GROSS
---------- ----- ---------- ---------- ----------
1 Scott 100 0 0
2 Tiger 500 0 0
SQL> select * From sal_hist;
no rows selected
SQL> update employee set basic = 200 where eno = 1;
1 row updated.
SQL> insert into employee (eno, ename, basic) values (3, 'King', 1000);
1 row created.
SQL> select * From employee;
ENO ENAME BASIC DA GROSS
---------- ----- ---------- ---------- ----------
1 Scott 200 10 210
2 Tiger 500 0 0
3 King 1000 50 1050
SQL> select * From sal_hist;
ENO SYS_DT OLD_BASIC
---------- ------------------- ----------
1 06.06.2020 11:10:49 100
3 06.06.2020 11:12:07
SQL>
CREATE DEFINER=`root`#`localhost` TRIGGER `TRIGGERNAME` AFTER UPDATE ON `employee` FOR EACH ROW
BEGIN
SET employee.da = employee.basic*(5.0/100)
SET employee.gross = employee.basic + (employee.basic*(5.0/100))
END
The way you have them defined both da and gross are derivable directly from base. However as a standard column I can update either of them directly. If this is not desirable, then you can declare them as virtual columns.
alter table employee drop (da, gross);
alter table employee add (
da generated always as base * 0.05 virtual
, gross generated always as base * 1.05 virtual
);
Now neither column can be updated independently and both are automatically updated when base is updated. You use them as normal columns of select, but DO NOT reference then in Insert or Update. And there is NO trigger needed.
See fiddle. Note: You did not specify what Oracle version you are using. This requires 11gR1 or higher.

Create a trigger on Delete customer that displays a message, "Customer Number 217 is deleted"

This is a homework problem.
The customer table consists of: customer_num,customer_name,street,city,state,postal_code,balance,credit_limit,rep_num. This table would be linked to the rep table via rep_num, and the orders table via customer_num. I have inserted a row into the customer table, just so I will not be deleting actual data, so my code to insert the row is:
insert into customer
values('217','Big Bird','123 Sesame
Street','Pittsburgh','PA','15301',1.00,100.00,'15');
I then set the server output on:
set serveroutput on;
Here is my code that is giving me the rejection of, "Warning: Trigger created with compilation errors.":
create or replace trigger print_customer_deleted
after delete on customer for each row
begin
delete customer_num
set on customer = on.customer - new.customer_num
where customer_num = :new.customer_num;
dbms_output.put_line('Customer number '||customer_num||
' is deleted');
end;
/
Also, would this be how my trigger would be executed? :
accept item_num prompt 'Enter customer number to be deleted: ';
execute print_customer_deleted('&customer_num');
I've created a TEST table based on Scott's DEPT. Trigger (after delete on DEPT) deletes a row from TEST and displays a message.
SQL> select * From dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> create table test as select * From dept;
Table created.
SQL> create or replace trigger trg_ad_dept
2 after delete on dept
3 for each row
4 begin
5 delete from test
6 where deptno = :old.deptno;
7
8 dbms_output.put_line('Department #' || :old.deptno ||' is deleted');
9 end;
10 /
Trigger created.
Let's see how it works:
SQL> delete from dept where deptno = 30;
Department #30 is deleted
1 row deleted.
SQL> select * From dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
40 OPERATIONS BOSTON
SQL> select * From test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
40 OPERATIONS BOSTON
SQL>
Seems to be OK - department #30 has been deleted from both tables & the message was displayed.
Apply it to your situation (I don't have your tables, and you didn't provide test case).

Select records from table where table name come from another table

We generate tables dynamically Eg. Table T_1, T_2, T_3, etc & we can get that table names from another table by following query.
SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC';
Now I want to get records from this retrieved table name. What can I do ?
I'm doing like following but that's not working :
SELECT * FROM (SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC')
FYI : I'm hitting two individual queries as of now though I want to eliminate one and I can not follow cursor/procedure approach due to some limitations.
A procedure which utilizes refcursor seems to be the most appropriate to me. Here's an example:
SQL> -- creating test case (your T_NAMES table and T_1 which looks like Scott's DEPT)
SQL> create table t_names (t_id number, t_key varchar2(3));
Table created.
SQL> insert into t_names values (1, 'ABC');
1 row created.
SQL> create table t_1 as select * from dept;
Table created.
SQL> -- a procedure; accepts KEY and returns refcursor
SQL> create or replace procedure p_test
2 (par_key in varchar2, par_out out sys_refcursor)
3 as
4 l_t_name varchar2(30);
5 begin
6 select 'T_' || t_id
7 into l_t_name
8 from t_names
9 where t_key = par_key;
10
11 open par_out for 'select * from ' || l_t_name;
12 end;
13 /
Procedure created.
OK, let's test it:
SQL> var l_out refcursor
SQL> exec p_test('ABC', :l_out)
PL/SQL procedure successfully completed.
SQL> print l_out
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
I could propose to you Dynamic SQL.
First of all, you need to create a cursor. The cursor will iterate by the dynamic tables. Then you could use dynamic SQL to create a query and then execute it.
So example:
https://livesql.oracle.com/apex/livesql/file/content_C81136WLRFYZF8ION6Q57GWE1.html - detailed cursor example.
https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm#i13057 - dynamic SQL in Oracle