Increment Multiple Timestamp Values with PL/SQL - oracle

I don't know Oracle at all, but I need to write something like this:
MySQL:
SET #serial:=1;
UPDATE table1 SET t = t + INTERVAL (#serial:=#serial+1) SECOND;`
Update and increment a timestamp by one second for all records. How to do this in Oracle?
Question Update:
My wording was not explaining my problem well enough.
I want to have a variable of (TimeStamp).
Then go through all records incrementing this variable with one second every time for a record update.

It should be like this as per my understanding
DECLARE
serial number := 1;
BEGIN
update table1 set t= t + (( serial + rownum - 1 )/86400);
END;
This will do increment like below
1st row -> 1 sec
2nd row -> 2 sec
.
.
nth row -> nsec
though the serial starts from 1

Another way would be
update table1 set t= t + interval '1' second;
Read more about Interval literals
As per your update, it should be
DECLARE
t_update_time date := sysdate;
BEGIN
update table1 set t=t_update_time + interval '1' second;
END;
This snippet assigns current datetime to t_update_time variable, and updates the record with 1 second added to the datetime declared in t_update_time. Change t_update_time assignment accordingly.
Without a PL/SQL switch it should be as
update table1 set t=to_date('21.01.2015 09:00:00','dd.mm.rrrr hh:mi:ss') + interval '1' second;

It's pretty simple actually. Just do:
update table1 set t = t + 1/86400;
After question update, you can do:
DECLARE
t_serial number;
cursor c is select * from table1 for update of t;
cr table1%rowtype;
BEGIN
t_serial := 1;
for cr in c loop
UPDATE table1 SET t = t_serial/86400 WHERE CURRENT OF c;
t_serial := t_serial + 1;
end loop;
END;

Related

Oracle: Update Every Row in a Table based off an Array

So i'm trying to create some seed data for a database that uses zip codes. I've created an array of 22 arbitrary zip code strings, and i'm trying to loop through the array and update one of the zips to every row in a table. Based on what I read and tried (I'm a 1st year, so I'm probably missing something), this should work, and does when I just output the array value based on the count of the table. this issue is in the row id subquery. When I run it in my console, it doesn't throw any errors, but it never completes and I think it's stuck in an infinite loop. How can I adjust this so that it will update the field and not get stuck?
declare
t_count NUMBER;
TYPE zips IS VARRAY(22) OF CHAR(5);
set_of_zips zips;
i NUMBER;
j NUMBER :=1;
BEGIN
SELECT count(*) INTO t_count FROM T_DATA;
set_of_zips:= zips('72550', '71601', '85920', '85135', '95451', '90021', '99611', '99928', '35213', '60475', '80451', '80023', '59330', '62226', '27127', '28006', '66515', '27620', '66527', '15438', '32601', '00000');
FOR i IN 1 .. t_count LOOP
UPDATE T_DATA
SET T_ZIP=set_of_zips(j)
---
WHERE rowid IN (
SELECT ri FROM (
SELECT rowid AS ri
FROM T_DATA
ORDER BY T_ZIP
)
) = i;
---
j := j + 1;
IF j > 22
THEN
j := 1;
END IF;
END LOOP;
COMMIT;
end;
You don't need PL/SQL for this.
UPDATE t_data
SET t_zip = DECODE(MOD(ROWNUM,22)+1,
1,'72550',
2,'71601',
3,'85920',
4,'85135',
5,'95451',
6,'90021',
7,'99611',
8,'99928',
9,'35213',
10,'60475',
11,'80451',
12,'80023',
13,'59330',
14,'62226',
15,'27127',
16,'28006',
17,'66515',
18,'27620',
19,'66527',
20,'15438',
21,'32601',
22,'00000')

In below program only for first two rows it is working and for other rows it is showing incorrect values in plsql

Here for the below program i need to print the amt_running_bal from the previous value. but it is not working and showing error. what is the error in the below program.Please provide any solution for this.
DECLARE
total Number := 1000000;
c_cod_acct_no Char;
c_amt_txn Number;
c_cod_drcr Char;
c_amt_running_bal Number;
amt_running_bal Number;
CURSOR c_chnos1 is
SELECT cod_drcr, amt_txn,amt_running_bal FROM chnos1;
BEGIN
OPEN c_chnos1;
FOR k IN 1..2 LOOP
FETCH c_chnos1 into c_cod_drcr,c_amt_txn,c_amt_running_bal;
if c_cod_drcr = 'C' then
total := total + c_amt_txn;
Update chnos1 SET amt_running_bal = total where cod_drcr='C' ;
elsif
c_cod_drcr = 'D' then
total := total - c_amt_txn;
Update chnos1 SET amt_running_bal = total where cod_drcr='D';
else
total := total + c_amt_txn;
Update chnos1 SET amt_running_bal = total where cod_drcr='C';
end if;
END LOOP;
CLOSE c_chnos1;
END;
/
Your query does not work as you limit the loop to k IN 1..2 so it will only read two rows from the cursor and there is no correlation between the row you are reading from the cursor and what you are updating; in fact, you are updating all the rows WHERE cod_drcr = 'C' or WHERE cod_drcr = 'D' and not just the current row. You could fix it by correlating the updates to the current row using the ROWID pseudo-column but it is an inefficient solution to use cursors as it will be slow and generate redo/undo log entries for each iteration of the cursor loop.
Instead, do it all in a single MERGE statement using an analytic SUM and a CASE expression:
MERGE INTO chnos1 dst
USING (
SELECT rowid AS rid,
1000000
+ SUM(
CASE cod_drcr
WHEN 'C' THEN +amt_txn
WHEN 'D' THEN -amt_txn
ELSE 0
END
)
OVER (
-- Use something like this to update each account
-- PARTITION BY cod_acct_no ORDER BY payment_date
-- However, you haven't said how to partition or order the rows so use this
ORDER BY ROWNUM
) AS total
FROM chnos1
) src
ON (dst.ROWID = src.rid)
WHEN MATCHED THEN
UPDATE SET amt_running_bal = src.total;
fiddle

Oracle trigger to increment value in another table after inserted in other

How to create trigger or procedure to add incrementally +1 in column VALUE in TABLE1 every single time when something is inserted in TABLE2 ?
Lets say that we start from VALUE.TABLE1 = 1 and I insert record in TABLE2. After that I should see 2 in VALUE column in TABLE1.
Then someone else is inserting record in TABLE2 and that procedure/trigger should add yet again +1 in VALUE and now it should be 3
etc.
DB is Oracle 11
Thanks.
Don't use table table1 and don't use a trigger.
Use a view instead:
create or replace view v_table1 as
select count(*) + 1 as value
from table2;
CREATE TRIGGER table2_trg
AFTER INSERT
ON table2
FOR EACH ROW
BEGIN
UPDATE table1 set value = value + 1;
END;
Or
CREATE or REPLACE TRIGGER TABLE2_trg
FOR INSERT
ON TABLE2
COMPOUND TRIGGER
cnt PLS_INTEGER := 0;
AFTER EACH ROW IS
BEGIN
cnt := cnt + 1;
END AFTER EACH ROW ;
AFTER STATEMENT IS
BEGIN
UPDATE table1 SET value = value + cnt;
END AFTER STATEMENT;
END;
I am not sure it is better or not and how it will work when some rows in table2 are dropped due to exceptions at the time of insertion.
It's better to use view if don't bother about deleted rows in table2.

PL/SQL cannot delete multiple rows

I have written simple code using PL/SQL to delete multiple rows from a table, but below code only deletes one row every i trigger it.
DECLARE
i number(2);
BEGIN
FOR i IN 1..4 LOOP
DELETE FROM table_name WHERE rownum = i;
dbms_output.put_line('i is: '|| i);
END LOOP;
END;
Can someone please suggest what is wrong with code?
ROWNUM is the nth row read.
select * from table_name where rownum = 1;
gets you the first row.
select * from table_name where rownum <= 2;
gets you the first two rows.
select * from table_name where rownum = 2;
gets you no rows, because you cannot read a second row without having read a first one.
This said, you'd have to replace
DELETE FROM table_name WHERE rownum = i;
with
DELETE FROM table_name WHERE rownum = 1;
But why would you do this anyway? Why delete arbitrarily picked records? Why use PL/SQL at all, rather than a mere DELETE FROM table_name WHERE rownum <= 4;?
What you need to understand is how Oracle processes ROWNUM. When assigning ROWNUM to a row, Oracle starts at 1 and only only increments the value when a row is selected; that is, when all conditions in the WHERE clause are met. Since our condition requires that ROWNUM is greater than 2 or equal to nth value, no rows are selected and ROWNUM is never incremented beyond 1.
If you really do wanna achieve it using PLSQL anot using SQL query as my friend Throsten has stated then please find a work around below.
I Created a dummy table test_c which holds 1 column (ID with number as its type).
set serveroutput on ;
DECLARE
i number(2);
j number(2);
counter number(10):=0;
BEGIN
FOR i IN 5..11 LOOP
if counter = 0 then
j:=i;
end if;
DELETE FROM test_c WHERE ID = (select id from (select id,rownum as ro from test_c order by id) where ro =j);
dbms_output.put_line('i is: '|| i);
counter:=counter+1;
END LOOP;
END;
Please note that this is not the right way to do it, but will work for your requirement.

How to select max value from a temporary table whose field is unnamed

I'm writing a PL/SQL function that needs to get dates from a few different tables and return the most recent one. My approach has been this:
Create a temporary table to hold the dates:
CREATE TYPE t_dates IS TABLE OF DATE;
/
Create a few local variables:
l_date DATE;
l_dates t_dates := t_dates();
l_idx INTEGER := 0;
l_output_date DATE;
Then select into a variable each date I'm interested in, and add it to the temporary table:
SELECT it.date
INTO l_date
FROM interesting_table it
WHERE it.id = 1
;
l_dates.extend;
l_idx := l_idx + 1;
l_dates(l_idx) := l_date;
After the temporary table has been populated, now I just want to select the max value from it. How do I do that? Something like...
SELECT max(*)
INTO l_output_date
FROM l_dates
;
RETURN l_output_date;
But I'm not sure I can reference my temporary table like that, nor how to find the max of a column that is unnamed.
Edit: When I test the above, I get an error: PL/SQL: ORA-00936: missing expression related to the line where I have SELECT max(*). However, I don't believe that this is my only error, because if I change the last block to:
SELECT *
INTO l_output_date
FROM l_dates
WHERE rownum = 1
;
which, just for testing, should select the first date in the temp table, then the error becomes PL/SQL: ORA-00942: table or view does not exist, which indicates to me that I can't refer to my temp table in this manner.
I have since learned from the comments that I should have max(column_value) rather than max(*), but using this, I still get the table or view does not exist error.
It is not possible to select from the nested tables, like you have tried.
You may have to use a logic to find the maximum value
l_idx := l_idx + 1;
l_dates(l_idx) := l_date;
if(l_date > l_dates(l_idx-1) OR l_idx =1) THEN
max_date :=l_date;
End if;
For your case, Rather than fetching a list of dates then getting the max date, you can find the max date in your query itself
SELECT max(it.date)
INTO l_date
FROM interesting_table it
WHERE it.id = 1
;

Resources