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;
Related
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).
This question was asked in one practical exams at my university.
Q: A table has following columnheads/columns:
medicine_name,medicine_manufacture_date,medicine_expiry_date.
As the columnhead names describe they have the respective data about a medicine in them.
Now they asked to write a pl/sql block to make list of all medicines' names which have expired(i.e.current system date is greater than the expirydate values of the medicine).
I strongly think that the column of sequential consecutive integers(like 1,2,3,...n) must be added to the table, which will act as a primary key to each medicine name.Medicine names are unique but to perform iterative operations they should posses an integer primary key.
Is it still possible to get the result without assigning an ineteger primary key?
I altered the table and assigned primary key to each record and wrote following block... It worked
but i want to do it without assigning a primary key. All possible smart ways will be adored!Plz suggest correction of any type in my code... My code is as follows:
declare
a date;
b date;
diff number(10);
medicine varchar(25);
begin
a:=sysdate;
for i in 1..5
loop
select medicine_expiry_date into b from med_details where med_id=i ;
diff:=trunc(a-b);
if
diff>0 then
select medicine_name into medicine from med_details where med_id=i;
dbms_output.put_line(medicine);
end if;
end loop;
end;
/
Try
BEGIN
DBMS_OUTPUT.PUT_LINE('The following medicines have expired:');
FOR aRow IN (SELECT MEDICINE_NAME
FROM MEDICINE
WHERE EXPIRY_DATE < SYSDATE)
LOOP
DBMS_OUTPUT.PUT_LINE(aRow.MEDICINE_NAME);
END LOOP;
END;
You could put an artificial primary key on this table if there was some need to have some other table refer to this one and no other practical candidate key was available, but it's not needed to answer the question as asked above.
Share and enjoy.
It looks straightforward... I suspect that there are some extra details.
/*
Q: A table has following columnheads/columns:
medicine_name,
medicine_manufacture_date,
medicine_expiry_date.
Now they asked to write a pl/sql block to make list of all medicines' names which have expired
(i.e.current system date is greater than the expirydate values of the medicine).
*/
-- SQL:
SELECT medicine_name
FROM a_table
WHERE medicine_expiry_date < SYSDATE;
-- PL/SQL v.1:
DECLARE
TYPE medicine_ntt IS TABLE OF a_table%ROWTYPE;
l_medicine medicine_ntt;
BEGIN
SELECT medicine_name
, medicine_expiry_date
BULK COLLECT INTO l_medicine
FROM a_table;
FOR indx IN 1..l_medicine.COUNT LOOP
IF l_medicine(indx).medicine_expiry_date < SYSDATE THEN
DBMS_OUTPUT.PUT_LINE(l_medicine(indx).medicine_name);
END IF;
END LOOP;
END;
-- PL/SQL v.2:
DECLARE
CURSOR medicine_cur IS
SELECT medicine_name
, medicine_expiry_date
FROM a_table;
TYPE medicine_ntt IS TABLE OF medicine_cur%ROWTYPE;
l_medicine medicine_ntt;
l_medicine_expired medicine_ntt := medicine_ntt();
BEGIN
OPEN medicine_cur;
FETCH medicine_cur BULK COLLECT INTO l_medicine;
CLOSE medicine_cur;
FOR indx IN 1..l_medicine.COUNT LOOP
IF l_medicine(indx).medicine_expiry_date < SYSDATE THEN
l_medicine_expired.EXTEND;
l_medicine_expired(l_medicine_expired.LAST) := l_medicine(indx);
END IF;
END LOOP;
FOR indx IN 1..l_medicine_expired.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(l_medicine_expired(indx).medicine_name);
END LOOP;
END;
Is there a way to iterate a cursor in a descending order using plsql?
I tried this:
FOR item IN REVERSE items
LOOP
-- do stuff
END LOOP;
but it seems to ignore the reverse key word.
Any suggestions?
It is the SQL clause that determines the order in which the data is traversed, so just apply an appropriate ORDER BY in the query.
DECLARE
cursor c1 is Select * FROM table_1
where (something)
order by (id..whatever you want) DESC; --decrement
v_variable.table%rowtype;
BEGIN
open c1;
fetch c1 into variable; -- will fetch first row...but it will be DESC
close c1;
END;
something like that...
OR
FOR i1 IN c1
LOOP
i1.id...
something...
END LOOP;
OR
FOR i2 IN (Select * FROM table_1
where (something)
order by (id..whatever you want) DESC)
LOOP
--something
END LOOP;
Since you don't have any column to order by, try using order by rownum
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.
i use oracle demo schema scott to do some plsql test ( the data in that schema are never changed ). i wrote the following program to get the employee number of each department. the problem is, there is just 4 departments but my program output 5 row. i can't find out the reason, anyone can help? great thanks.
declare
cursor employees(department_id number) is
select count(*) howmany
from scott.emp
where deptno=department_id;
employees_per_dept employees%rowtype;
cursor departments is
select *
from scott.dept;
a_department departments%rowtype;
begin
dbms_output.put_line('-----------------------------------');
open departments;
loop
exit when departments%notfound;
fetch departments into a_department;
open employees(a_department.deptno);
fetch employees into employees_per_dept;
dbms_output.put_line(employees_per_dept.howmany);
close employees;
end loop;
close departments;
dbms_output.put_line('-----------------------------------');
end;
If you output the deptno in the dbms_output you'll see the reason.
You need to switch these two lines:
fetch departments into a_department;
exit when departments%notfound;
%NOTFOUND is meaningless before the initial FETCH; your code was counting the emps in the last dept twice.
declare
cursor cl(ccode varchar2) is
Select * from employees where department_id=ccode;
z cl%rowtype;
cnt number:=0;
begin
Open cl('90');
fetch cl into Z;
while (cl%found) loop
dbms_output.put_line ( 'nsme is ' || z.last_name);
fetch cl into Z;
cnt := cnt +1;
end loop;
dbms_output.put_line (cnt);
close cl;
end;