Comparing column in PL/SQL - plsql

I have 2 tables, Driver and Mechanic and in both table they have a same column Employee#
How do i check both tables using PL/SQL so that an employee in Driver table cannot appear in the Mechanic table by comparing the employee#. And if it happens, it would display a message "Employee# cant be both driver and mechanic!"
I do know that i could simply just compare both table using:
SELECT Employee#
FROM Driver
INTERSECT
SELECT Employee#
FROM Mechanic
But its a requirement for me to use PL/SQL.
I've tried using cursor but i cant seem to make it run through the entire column. Here are my code:
declare
cursor c1 is select employee# from driver;
cursor c2 is select employee# from mechanic;
driverenum number(30);
mechanicenum number(30);
begin
open c1;
fetch c1 into driverenum;
close c1;
open c2;
fetch c2 into mechanicenum;
close c2;
if driverenum in (mechanicenum) then
dbms_output.put_line(driverenum);
end if;
end;
/

If the only requirement is that you use PL/SQL
DECLARE
TYPE emp_nt IS TABLE OF driver.employee#%type;
l_drivers emp_nt;
l_mechanics emp_nt;
l_both emp_nt;
BEGIN
SELECT employee#
BULK COLLECT INTO l_drivers
FROM driver;
SELECT employee#
BULK COLLECT INTO l_mechanics
FROM mechanic;
l_both := l_drivers MULTISET INTERSECT l_mechanics;
FOR i IN 1 .. l_both.count
LOOP
dbms_output.put_line( 'Employee ' || l_both(i) ||
' is employed as both a driver and a mechanic' );
END LOOP;
END;
This approach would potentially occupy quite a bit of space in the PGA if there are a large number of rows in either table. But normally it would be almost as efficient as the SQL solution.

Related

My code takes too much time for execution is there any efficient way to do this

Here there is 3 table
1.employee(eid,ename),
2.address(aid,address),
3.employee_add(eid,aid)
employee and address has many to many relation in it.what I need to do is to clean the duplicate from address table without any data loss from employee_add table. thanks in advance! please help
DECLARE
a ADDRESS.AID%TYPE;
b ADDRESS.ADDRESS%TYPE;
c ADDRESS.AID%TYPE;
d ADDRESS.ADDRESS%TYPE;
CURSOR Cur1 IS
SELECT AID,ADDRESS
FROM ADDRESS;
CURSOR Cur2 IS
SELECT AID,ADDRESS
FROM ADDRESS;
BEGIN
OPEN Cur1;
LOOP
FETCH Cur1 INTO a, b;
EXIT WHEN Cur1%NOTFOUND;
OPEN Cur2;
LOOP
FETCH Cur2 into c,d;
IF (b=d) THEN
IF(a!=c) THEN
update employee_add set aid=a where aid=c;
delete from address where aid=c;
END IF;
END IF;
END LOOP;
CLOSE Cur2;
END LOOP;
CLOSE Cur1;
END;
You should be able to do this using the following SQL statements (which you could put inside a PL/SQL procedure if you wanted to), like so:
-- To update the employee_add tables
MERGE INTO employee_add tgt
USING (SELECT ea.rowid rid,
a.aid,
a.address,
MIN(aid) OVER (PARTITION BY address) new_aid
FROM address a
INNER JOIN employee_add ea ON ea.aid = a.aid) src
ON (tgt.rowid = src.rid)
WHEN MATCHED THEN
UPDATE SET tgt.aid = src.new_aid
WHERE tgt.aid != src.new_aid;
-- Delete any rows now longer in the employee_add table
DELETE FROM address
WHERE aid NOT IN (SELECT aid FROM employee_add);
-- If you need to deduplicate the employee_add table, this should do the trick:
DELETE FROM employee_add ea1
WHERE ROWID > (SELECT MIN(ROWID)
FROM employee_add ea2
WHERE ea1.eid = ea2.eid
AND ea1.aid = ea2.aid;
In general, explicit cursor is slower than implict cursor.
You can try to convert the
OPEN ...
LOOP
FETCH ...
EXIT WHEN ...
...
...
END LOOP;
into
FOR ... LOOP
...
END LOOP;
else, it would help if you provide some DDLs & DMLs (together with PK, indexes and constraints).

Teradata Insert Count into Variable

Description what I am trying to do:
I have 2 environments one has data (X) second one has no data (Y).
I have done procedure which has input parameter P_TableName. It should check if in this table is any data and IF There is then we will take data to Y environment.
So Mostly it works but I have problem with one freaking simple thing ( I have not much experience in TD but in Oracle it would be a 10seconds).
I need to pass select count(*) from X to variable how to do that?.
I was trying by SET VAR = SELECT...
INSERT INTO VAR SELECT...
I was trying to make a variable for statement which is directly executing
SET v_sql_stmt = 'INSERT INTO ' || VAR|| ' SELECT COUNT(*) FROM ' || P_TableName;
CALL DBC.SYSEXECSQL(v_sql_stmt);
It's probably really simple thing but I can't find good solution for that. Please help
You'll have to open a cursor to fetch the results since you are running dynamic SQL. There is a good example in the Teradata help doc on Dynamic SQL:
CREATE PROCEDURE GetEmployeeSalary
(IN EmpName VARCHAR(100), OUT Salary DEC(10,2))
BEGIN
DECLARE SqlStr VARCHAR(1000);
DECLARE C1 CURSOR FOR S1;
SET SqlStr = 'SELECT Salary FROM EmployeeTable WHERE EmpName = ?';
PREPARE S1 FROM SqlStr;
OPEN C1 USING EmpName;
FETCH C1 INTO Salary;
CLOSE C1;
END;
You can't use INTO in Dynamic SQL in Teradata.
As a workaround you need to do a cursor returning a single row:
DECLARE cnt BIGINT;
DECLARE cnt_cursor CURSOR FOR S;
SET v_sql_stmt = ' SELECT COUNT(*) FROM ' || P_TableName;
PREPARE S FROM v_sql_stmt;
OPEN cnt_cursor;
FETCH cnt_cursor INTO cnt;
CLOSE cnt_cursor;

dynamically change column in oracle cursor

I have 50 columns in one table and need to update each column.
Trying the below plsql code. (commented update section is working).
But dynamically generated column is not accepting.
(PL/SQL: ORA-01747: invalid user.table.column, table.column, or column specification)
Anybody can help please?
DECLARE
cursor udas is
select 5109 as udaid from dual
union all
select 8209 as udaid from dual;
BEGIN
for uda in udas loop
DECLARE
cursor c1 is
select
x.item, x.uda_id, x.uda_value, x.uda_value_desc
from
hp2_uda_data x
where
x.uda_type='LOV'
and x.uda_id=uda.udaid;
begin
for i in c1 loop
begin
/*update testtable set item_uda_5109_v=i.uda_value,
item_uda_5109_d=i.uda_value_desc where item_code=i.item;*/
update testtable set 'item_uda_'||uda.udaid||'_v'=i.uda_value,
'item_uda_'||uda.udaid||'_d'=i.uda_value_desc where item_code=i.item;
end;
end loop;
commit;
end;
end loop;
END;
Dynamic code requires execute immediate:
execute immediate
'update testtable
set item_uda_'||uda.udaid||'_v = :b1
, item_uda_'||uda.udaid||'_d = :b2
where item_code = :b3'
using i.uda_value, i.uda_value_desc, i.item;
It can be useful to construct the dynamic code in a variable so that you can report or log it in the event of failure.
I also recommend looking into code indentation as a useful technique for making code readable.

FOR UPDATE CURSOR in teradata?

This is sql block i'm using in Oracle,
Now I need to do the same way in Teradata, Is possible? I want the syntax FOR UPDATE CURSOR in Teradata!
Can you please guide me?
declare
cursor c1 is select * from Employees FOR UPDATE;
a number :=0 ;
begin
for x in c1 loop
a := a +1 ;
update employees set salary = a where current of c1;
end loop;
end;
Updateable cursors are allowed in ANSI-mode sessions only.
The syntax is quite similar:
declare c1 cursor for
select * from Employees FOR UPDATE;
a number :=0 ;
begin
for x in c1 loop
a := a +1 ;
update employees set salary = a where current of c1;
end loop;
end;
But cursors perform really bad in a parallel DBMS like Teradata as they're processed serially, one row after the other.
In almost every case cursors on data can be rewritten set-based (e.g. your example is a simple ROW_NUMBER) and then they perform several orders of magnitude faster.
Maybe you could use this instead?
UPDATE employees
FROM (
SELECT csum(1,1) new_salary, emp_id
FROM employees
) src
set salary=src.new_salary
where employees.emp_id=src.emp_id;

Print Oracle Pl/sql Cursor

Can I directly open and print cursor in begin end block without using loops?
or without reading each column and printing it individually for each row.
If you want to display one record there is no need for looping in your cursor.
If multiple then you need looping in cursor.
Eg In **Test_Project** Table has two column:-
projectid projectname
p2 Programming
p1 Search Engine
p3 Testing
--Below is the code to display one record without using loop
Declare
cprojname varchar2(2000) ;
CURSOR c1
IS
select project_name from test_project WHERE projectid='p1';
BEGIN
OPEN c1;
FETCH c1 INTO cprojname;
if c1%notfound then
cprojname := 'no data';
else
dbms_output.put_line(cprojname);
end if;
CLOSE c1;
END;
o/p:- Search Engine

Resources