PL/SQL Output column results in dbms_output.put_line LOOP - sql

Good morning,
I will start out saying that I have already done 97% of this as yes, it is homework. The ONLY part I am confused with is not understanding the Error that is given. I had to create a loop that would take 2 numbers given and then output which numbers both are commonly divisible by. Here is that code:
SET SERVEROUTPUT ON SIZE UNLIMITED
--DROP TABLE IF IT EXISTS
DROP TABLE TESTER1 cascade constraints;
--CREATE TESTER1 TABLE
CREATE TABLE TESTER1 (xnum number, num1 number, num2 number);
--DECLARE VARIABLES
DECLARE
Test_Number1 number := 10;
Test_Number2 number := 20;
x number := 1;
--BEGIN
BEGIN --OUTSIDE LOOP
LOOP
BEGIN --INSIDE LOOP
INSERT INTO TESTER1(xnum,num1,num2)
VALUES(x,MOD(Test_Number1,x),MOD(Test_Number2,x));
x := x + 1;
EXIT WHEN NOT x < 20;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('error');
END;
END LOOP; --INSIDE LOOP
END; --OUTSIDE LOOP
/
I then wrote a SELECT statement to find where both have a common divisor:
SELECT xnum FROM tester1
where num1=num2;
My Question is: How do I loop through the results from the table Tester1 and use dbms_output.put_line() so each result from the SELECT statement is inserted until it loops through 3 rows?
I hope I explained it well enough. I am using Oracle 12c.

Ok, so the answer I have found and just need to try and incorporate into my previous statement is:
BEGIN
FOR r_xnum IN (SELECT xnum FROM tester1
where num1=num2)
LOOP
dbms_output.put_line('Common factor: ' ||r_xnum.xnum);
END LOOP;
END;
/
Thanks again for all that pointed me in the right direction. It has been awhile since I posted here last so not sure how to close out the question without completely deleting it, so I will keep it how it is unless someone else knows how. EDIT I have to wait 2 days until I can accept my own answer
Final run:
SET SERVEROUTPUT ON SIZE UNLIMITED
--DROP TABLE IF IT EXISTS
DROP TABLE TESTER1 cascade constraints;
--CREATE TESTER1 TABLE
CREATE TABLE TESTER1 (xnum number, num1 number, num2 number);
--DECLARE VARIABLES
DECLARE
Test_Number1 number := '&input1';
Test_Number2 number := '&input2';
x number := 1;
--BEGIN
BEGIN --LOOP 1
LOOP --LOOP FOR INSERT
BEGIN --INSIDE LOOP
INSERT INTO TESTER1(xnum,num1,num2)
VALUES(x,MOD(Test_Number1,x),MOD(Test_Number2,x));
x := x + 1;
EXIT WHEN NOT x < 20;
END;
END LOOP; --LOOP 1
BEGIN --LOOP FOR SELECT
dbms_output.put_line('The two numbers enetered are ' ||Test_Number1|| 'and '||Test_Number2);
FOR r_xnum IN (SELECT xnum FROM tester1
where num1=num2)
LOOP
dbms_output.put_line('Common factor: ' ||r_xnum.xnum);
END LOOP;
END;
END;
/

Related

Cheking if an entry exists in another table using cursor

My task is to insert entries from one table to another by using parametrized cursor. Here's what I have tried
DECLARE
oldroll NUMBER;
newroll NUMBER;
oldname VARCHAR2(25);
newname VARCHAR2(25);
CURSOR c_orollcall (roll_no NUMBER,name VARCHAR2) IS SELECT * FROM o_rollcall;
PROCEDURE procedure_2;
PROCEDURE procedure_2 AS
BEGIN
OPEN c_orollcall;
LOOP
FETCH c_orollcall INTO oldroll ,oldname;
SET #count = 0;
SELECT roll_no INTO #count FROM n_rollcall WHERE EXISTS (oldroll);
IF #count>0 THEN
DBMS_OUTPUT.PUT_LINE('ENTRY ALREADY EXISTS');
ELSE
INSERT INTO n_rollcall VALUES (oldroll,oldname);
END IF;
EXIT WHEN c_orollcall%NOTFOUND;
END LOOP;
CLOSE c_orollcall;
END;
/
BEGIN
procedure_2;
END
/
I am getting a bunch of errors and dont' understand how to proceed further.I previously posted a question about this too but it generated more errors .
here's the problem statement:
Write a PL/SQL block of code using parameterized Cursor that will merge the data available in
the newly created table N_RollCall with the data available in the table O_RollCall. If the data in
the first table already exist in the second table then that data should be skipped.
I would suggest you to use an extra variable to store the result and check it in IF codition
SET count = 0;
SELECT COUNT(roll_no) INTO count FROM n_rollcall WHERE EXISTS (oldroll);
Updated code:
CREATE OR REPLACE PROCEDURE procedure_2 AS
DECLARE count INT default 0;
BEGIN
OPEN c_orollcall;
LOOP
FETCH c_orollcall INTO oldroll ,oldname;
SET count = 0;
SELECT roll_no INTO count FROM n_rollcall WHERE EXISTS (oldroll);
IF count>0 THEN
DBMS_OUTPUT.PUT_LINE('ENTRY ALREADY EXISTS');
ELSE
INSERT INTO n_rollcall VALUES (oldroll,oldname);
END IF;
EXIT WHEN c_orollcall%NOTFOUND;
END LOOP;
CLOSE c_orollcall;
END;
/

Trigger to count insert and updates from users

I'm new with oracle sql. I am trying to make a trigger that counts when X user performs an update or an insert, but the TRANSACTIONCONTROL table shows it like this:
DATE--------- USER-----------INSERT----UPDATE
10/03/2022 UserParcial 1 0
10/03/2022 UserParcial 0 1
10/03/2022 UserParcial 1 0
But I want it to look like this:
DATE--------- USER-----------INSERT----UPDATE
10/03/2022 UserParcial 2 1
This is my trigger:
create or replace NONEDITIONABLE TRIGGER TRANSACTIONCONTROL_Trig
AFTER INSERT OR DELETE OR UPDATE on products
for each row
DECLARE
dataTran date;
userTran varchar(30);
InsertTran number:=0;
UpdateTran number:=0;
BEGIN
SELECT SYSDATE INTO dateTran FROM DUAL;
SELECT USER INTO userTran FROM DUAL;
IF INSERTING THEN
InsertTran := InsertTran +1;
INSERT INTO TransactionControl(date, user, insert, updates)
VALUES(dateTran, userTran, insertTran, updateTran);
END IF;
IF UPDATING THEN
updateTran:= updateTran+1;
INSERT INTO TransactionControl(date, user, insert, updates)
VALUES(dateTran, userTran, insertTran, updateTran);
END IF;
END;
If you don't need exact numbers, than mining ALL_TAB_MODIFICATIONS periodically could probably suffice. (I'm curious as to what business function having the count provides)
But if you really must use a trigger, then a compound trigger lets you keep counts at row level, but then summarise at statement level.
Some pseudo code below
create or replace trigger mytrig
for insert or update on mytable
compound trigger
ins_cnt int;
upd_cnt int;
before statement is
begin
ins_cnt := 0;
upd_cnt := 0;
end before statement;
after each row is
begin
if inserting then ins_cnt := ins_cnt + 1; end if;
if updating then upd_cnt := upd_cnt + 1; end if;
end after each row;
after statement is
begin
insert into txn_control ( ... ) values (ins_cnt, upd_cnt);
end after statement;
end;
/

How do I run a count of rows over a database link?

This code, works. It runs a row count the way you'd expect, I want to tweek it, mostly to do a count over a db_link for tables dictated as I see fit.
declare
n number;
begin
for i in (select table_name from user_tables) loop
execute immediate' select count(*) from '||i.table_name into n;
dbms_output.put_line('Table Name: '||i.table_name||' Count of Row''s: '||n);
end loop;
end;
/
So, this is the adapted code... it includes a variable with the name of the link. (The link works fine) But how to reference it is probably where I'm coming unstuck.
declare
l_dblink varchar2(100) := 'DB1';
n number;
begin
for i in (select table_name from my_tables) loop
execute immediate' select count(*) from '||i.table_name#||l_dblink into n;
dbms_output.put_line('Table Name: '||i.table_name||' Count of Row''s: '||n);
end loop;
end;
/
Can someone please have a look and tell me where I'm going wrong? I just want the SQL to pick up the table names from a local table, and then use the names to count the rows in those tables, which reside in the remote database.
Monkey is on the wrong tree and can't eat a banana.
SQL> create table my_tables (table_name varchar2(20));
Table created.
SQL> insert into my_tables values ('dual');
1 row created.
SQL> set serveroutput on
SQL> declare
2 l_dblink varchar2(100) := 'db1';
3 n number;
4 begin
5 for i in (select table_name from my_tables) -- has to be like this
6 loop -- vvv
7 execute immediate' select count(*) from '||i.table_name || '#' || l_dblink into n;
8 dbms_output.put_line('Table Name: '||i.table_name||' Count of Row''s: '||n);
9 end loop;
10 end;
11 /
Table Name: dual Count of Row's: 1
PL/SQL procedure successfully completed.

update millions of rows in oracle

I am trying to update 5 million rows. Below query runs in 5-6 minutes. But I want to have periodic commit in between 500000 records. How do i do that?
Any help is appreciated.
Thanks
DECLARE
a NUMBER;
BEGIN
UPDATE table1
SET (name) =
(SELECT name
FROM table1
WHERE a1= 24672
WHERE ROWNUM <= 6500000;
a := SQL%ROWCOUNT;
DBMS_OUTPUT.put_line (a || ' Rows Updated');
END;
/
Since you have tagged this 'optimization' I assume you care about performance. Whilst you could rewrite your SQL in PL/SQL, use a loop and commit every n iterations, this is going to slow you down.
The fastest way to update millions of rows is often in fact not to update at all. Instead you create a new table (CREATE TABLE ... AS ... SELECT ), drop your old table and then rename your new table. It reduces the amount of redo and undo and greatly speeds up performance.
See How to update millions of rows
If performance is good enough then possibly you no longer care about partial commits?
You could probably do something similar to this.
DECLARE
a NUMBER;
commitCt NUMBER;
rowCt NUMBER;
BEGIN
LOOP
commitCt := 0;
rowCt := 0;
SAVEPOINT svePoint;
WHILE rowCt/500000 <= 1
LOOP
BEGIN
rowCt := rowCt + 1;
commitCt := commitCt + 1;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK to svePoint;
END;
END LOOP;
COMMIT;
IF commitCt = 0 THEN
EXIT;
END IF;
END LOOP;
END;
/

Oracle SQL developer debugging index table

Is there a bug in SQL developer, or limitation
I'm trying to see values in index table fields, but it shows me only 20 fields???
here is my example code below I'm looping 30 time, but in debug screen shows only 20.
Does anyone know how I can see all fields?
CREATE OR REPLACE PROCEDURE TEST AS
TYPE Fieldvalue IS TABLE OF VARCHAR2 (100)
INDEX BY BINARY_INTEGER;
Field_Position Fieldvalue;
BEGIN
for i in 1..30 loop
Field_Position(i) := 'hello ' || i;
end loop;
dbms_output.put_line('hello');
END TEST;
I put debug break point on dbms_output.put_line('hello'); and it show only 20 records?
Without using the debug screen on sql developer, you can just loop through the array (field_position) to see its content.
CREATE OR REPLACE PROCEDURE TEST AS
TYPE Fieldvalue IS TABLE OF VARCHAR2 (100)
INDEX BY BINARY_INTEGER;
Field_Position Fieldvalue;
BEGIN
for i in 1..30 loop
Field_Position(i) := 'hello ' || i;
END loop;
FOR A IN FIELD_POSITION.FIRST..FIELD_POSITION.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(FIELD_POSITION(A));
END LOOP;
END TEST;
/
BEGIN
TEST;
END;