How to fix LOOP error PostgreSQL while trying to Select - sql

Here is the code I'm Testing :
DO $$
DECLARE
i INT := 0;
BEGIN
WHILE i <= numberUsers
BEGIN
SELECT COUNT(*) FROM "Users";
SET i := i + 1;
END;
END $$;
But when I try to execute it it return me this error :
ERREUR: « LOOP » manquant à la fin de l'expression SQL
LIGNE 7 : SELECT COUNT(*) FROM "Users";
Kind Regards !

You have considerable structural errors in your code block:
DO $$
DECLARE
i INT := 0;
BEGIN
WHILE i <= numberUsers --<<< numberUsers is undefined and uninitialized
BEGIN --<<< this starts a nested block should be LOOP
SELECT COUNT(*) FROM "Users"; --<<< in a block you must tell plpgsql what to do with the result
SET i := i + 1; --<<< assignment does not use SET in plpgsql
END; --<<< terminated nested block, should terminate loop
END $$;
Correcting all the points from the block becomes:
do $$
declare
i int := 0;
numberusers int;
begin
select count(*)
into numberusers
from "users";
while i <= numberusers
loop
i := i + 1;
end loop;
end $$;

Per:
https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-CONTROL-STRUCTURES-LOOPS
WHILE boolean-expression LOOP
statements
END LOOP [ label ];
You need the LOOP END ... LOOP portions of the statement.

The error message tells you that something is missing from the expression, which is a clear indication that you have a syntax error. Try this code:
DO $$
DECLARE
i INT := 0;
BEGIN
WHILE i <= numberUsers LOOP
BEGIN
SELECT COUNT(*) FROM "Users";
SET i := i + 1;
END LOOP;
END $$;
Read more here: https://www.postgresqltutorial.com/plpgsql-while-loop/

DO $$
BEGIN
DECLARE
i INT := 0;
BEGIN
WHILE i <= numberUsers LOOP
SELECT COUNT(*) FROM "WU_Users";
i := i + 1;
END LOOP;
END $$;
But it's returning me this now :
psql:matching.sql:12: ERREUR: label de fin « matching » spécifié pour un bloc sans label
LIGNE 12 : END matching $$;

Related

How to browse an query id not follow PostgreSQL

I need your help about an modification of my actual code. Here it is :
\timing on
DO $$
BEGIN
DECLARE
i INT := 1; -- valeur de départ à changer pour la range d'id
j INT := i + 1;
numberUsers INT; -- Changer valeur numberUsers pour fin de la range d'id
commonSkills INT;
random INT;
idSphere INT := 2;
BEGIN
SELECT COUNT(*) INTO numberUsers FROM "WU_Users"; -- si numberUSers est modifié, commentez la ligne
WHILE i < numberUsers LOOP
WHILE j <= numberUsers LOOP
IF i !=j THEN
SELECT floor(random() * 10 + 35)::INT INTO random;
INSERT INTO "WU_MatchingUsers"("IDWU_User1", "IDWU_User2", "MatchingScore")
VALUES(i, j, random)
ON CONFLICT ("id")
DO
UPDATE SET "MatchingScore" = EXCLUDED."MatchingScore";
ELSE
RAISE NOTICE 'Same Users';
END IF;
j := j + 1;
END LOOP;
j := i + 1;
RAISE NOTICE 'i: %', i;
i := i + 1;
END LOOP;
END;
END $$;
\timing off
So this code take two id, and with two loops "browse" from i to numberUsers and insert into another table a random matching score, now I need to add this :
SELECT "IDWU_Users_WU_Users" FROM "WU_UsersSpheres" WHERE "IDWU_UsersSpheres" = idSphere;
This line return me a list of id from another table that I need to match, like the script above I match in this order :
1/2
1/3
etc etc
But now this new line can return me id like that :
532
1426
3236
84697
And I need to make the same matching system than before so like that :
532/1426
532/3236
532/84697
Kind Regards !

Multiple FORALL in a orasql procedure

Im trying to both delete then update some data from a table inside a procedure. It is my understanding that both can't be done in the same FORALL statement and that I can do multiple FORALL using the same cursor. The problem is that the second FORALL does not seem to do anything. Is there something that im not getting? Here is the code :
cursor cPARTY is
SELECT /* +parallel(4) */ DISTINCT p.ID,
CASE WHEN sf.PARTYID is null THEN 'delete'
ELSE 'switch'
END AS action,
pa.SOURCESYSTEMLID as sources
FROM CV_CLAIMS_TRAVEL.EPUR_PARTY p
LEFT JOIN CV_CLAIMS_TRAVEL.STAR_FILE sf ON sf.PARTYID = p.ID
LEFT JOIN CV_CLAIMS_TRAVEL.PARTY pa ON pa.ID = p.ID;
type type_party is TABLE OF cPARTY%ROWTYPE INDEX BY PLS_INTEGER;
t_party type_party;
nLOT pls_integer := 1;
nbDeleted int :=0;
nbSwitched int := 0;
begin
p_tableName := 'PARTY(INDIVIDU)';
allBEGIN_TIMESTAMP := systimestamp;
open cPARTY;
loop
lotBEGIN_TIMESTAMP := systimestamp;
dbms_application_info.set_module('CV_CLAIMS_TRAVEL.PARTY',trim(to_char(nLOT * nLIMIT,'999G999G999')));
FETCH cPARTY BULK COLLECT
INTO t_party
limit nLIMIT;
exit when t_party.count = 0;
p_nbLinesTransfered :='Erreur: Suppression de données';
dbms_application_info.set_module('CV_CLAIMS_TRAVEL.PARTY - DELETING',trim(to_char(nLOT * nLIMIT,'999G999G999')));
FORALL i IN t_party.FIRST .. t_party.LAST
DELETE /*+parallel(4)*/ FROM CV_CLAIMS_TRAVEL.PARTY
WHERE ID = t_party(i).ID
AND t_party(i).action = 'delete';
nbDeleted := nbDeleted + sql%rowcount;
FORALL i IN t_party.FIRST .. t_party.LAST
UPDATE CV_CLAIMS_TRAVEL.PARTY
SET UPDATEDATE = sysdate, SOURCESYSTEMLID = 'SOURCE_SYSTEM:0000000000', UPDATEDBYUSERID = 'CV_CLAIM_INTEG'
WHERE ID = t_party(i).ID
AND t_party(i).sources='SOURCE_SYSTEM:0000000004'
AND t_party(i).action = 'switch';
nbSwitched := nbSwitched + sql%rowcount;
commit;
lotEND_TIMESTAMP :=systimestamp;
trc.trc_message('lotELAPSED '||to_char(nLOT * nLIMIT,'999G999G990')||' Rows. ELAPSED '|| replace(substr(to_char(lotEND_TIMESTAMP - lotBEGIN_TIMESTAMP, 'HH24:MI:SS.FF3'),1,20),'+000000 ','+'));
nLOT := nLOT + 1;
end loop;
close cPARTY;
commit;
gather_stats('CV_CLAIMS_TRAVEL', 'PARTY');

I keep getting an error when trying to execute my code

Declare
Total integer;
i integer;
Begini:= 1;
total:=1;
loop
total := total * i;
i := i+1;
exit when i > 4;
End loop;
dbms_output.put_line('total is ' || total);
End;
For start
Begini:= 1;
total:=1;
Should be
Begin
i:= 1;
total:=1;

PLSQL Printing prime numbers

I want to print prime numbers between 1 to 50. But I don't understand what I am doing wrong in my code. After BEGIN, SQLDeveloper says I had an error because it expected another sign and not = .
SET SERVEROUTPUT ON
DECLARE
i NUMBER;
counter NUMBER;
n NUMBER;
k NUMBER;
BEGIN
i := 2;
counter := 0;
n := 50;
k := n/2;
FOR i IN 1..k LOOP
IF (n%i := 0 ) THEN
counter := 1;
END IF;
IF (counter := 0) THEN
DBMS_OUTPUT.PUT_LINE(n||' is prime number');
END IF;
END LOOP;
END;
SET SERVEROUTPUT ON
DECLARE
i NUMBER;
counter NUMBER;
n NUMBER;
k NUMBER;
BEGIN
i := 2;
counter := 0;
n := 50;
k := floor(n/2);
FOR i IN 1..k LOOP
IF (mod(n, i) = 0 ) THEN
counter := 1;
END IF;
IF (counter = 0) THEN
DBMS_OUTPUT.PUT_LINE(n||' is prime number');
END IF;
END LOOP;
END;
k := n/2; -- added FLOOR (k is NUMBER, by default it's NUMBER(38, max_scale))
IF (n%i := 0 ) THEN -> IF (mod(n, i) = 0 ) THEN
Oracle has MOD function for remainder + to compare you need to use =,
:= is for assignment.
DECLARE
counter NUMBER;
k NUMBER;
BEGIN
FOR n IN 1..50 LOOP
counter := 0;
k := floor(n/2);
FOR i IN 2..k LOOP
IF (mod(n, i) = 0 ) THEN
counter := 1;
END IF;
END LOOP;
IF (counter = 0) THEN
DBMS_OUTPUT.PUT_LINE(n||' is prime number');
END IF;
END LOOP;
END;
In your IF clause you are assigning the value instead of comparison. You are using := operator, where you shd be using =
It shud be like (IF counter = 0) then
......
Also I dont think n%i would work, you could do IF (trunc(n) = n) then ... or IF (mod (n,i) =0) then ...
--this function is check prime number.
create or replace function prime_a(x number) return
varchar2 is
n integer;
ans varchar2(50);
begin
n:=(x/2);
for i in 2..n loop
if mod(x,i)=0
then ans:='not a prime';
exit;
else ans:='prime';
end if;
end loop;
return ans;
end;
/
step-1:
create table tob(prime number);
step-2:
create or replace procedure ro(m number,n number)
is
a integer;
co Boolean;
begin
for j in m..n loop
co:=false;
co:=(j=1 );
a:=(j/2);
for i in 2..a loop
co:=(mod(j,i)=0);
exit when co;
end loop;
if(not co) then
insert into tob values(J);
end if;
end loop;
commit;
end;
/
step-3:
exec ro(1,50);
step-4: check:-
select * from tob;
You should create or replace in your source code:
function prime_a(x number) return
varchar2 is
n integer;
ans varchar2(50);
begin
n:=(x/2);
for i in 2..n loop
if mod(x,i)=0
then ans:='not a prime';
exit;
else ans:='prime';
end if;
end loop;
return ans;
end;
/
Why don't you just check for previous prime divisibility?
create table prime (primeno bigint)
declare #counter bigint
set #counter = 2
while #counter < 1000000
begin
if not exists(select top 1 primeno from prime where #counter % primeno = 0)
insert into prime select #counter
set #counter = #counter + 1
end
select * from prime order by 1
You could certainly cap the numbers you are checking against in the where condition to reduce your overheads further.
declare
i number;
j number;
k number:=0;
begin
for i in 1..50
loop
for j in 2..i-1
loop
if mod(i,j)=0 then
k:=1;
exit;
end if;
end loop;
if k=0 then
dbms_output.put_line(i);
end if;
k:=0;
end loop;
end;
/
create or replace function prime_a(x number) return varchar2 is
n integer;
ans varchar2(50);
begin
n:=(x/2);
for i in 2..n loop
if mod(x,i)=0 then
ans:='not a prime';
exit;
else
ans:='prime';
end if;
end loop;
return ans;
end;
/

Skip invalid cursor and continue loop

I have the below procedure were the loop is breaking if the cursor does not have any record in it. I would like to contine the iteration even if the cursor does not have any record.
My procedure is,
CREATE OR REPLACE PROCEDURE "MAPSADMIN"."FORECAST_MAINTENANCE_SCH" (
in_carrierCode VARCHAR2,
in_WindowPeriodStr VARCHAR2,
out_forecastRecords OUT types.cursortype
)
IS
vtailAndCheckCur types.cursortype;
vForecastRecsCursor types.cursortype;
vtailNo VARCHAR2(10);
vmaintCheckType VARCHAR2(10);
vforcastRecords forecastObjectsList := forecastObjectsList();
forcastRec forecastObjectsList := forecastObjectsList();
BEGIN
dbms_output.enable(null);
OPEN vtailAndCheckCur FOR
select td.tail_number,mpm.maint_check_type
from tail_details td, maint_plan_tail_map mptm, maint_plan_master mpm
where td.tail_number = mptm.tail_number
and mpm.maint_plan_code = mptm.maint_plan_code
and mpm.carrier_code = in_carrierCode
UNION
select td.tail_number,mpm.maint_check_type
from tail_details td, maint_plan_subfleet_map mptm, maint_plan_master mpm
where td.subfleet_code = mptm.subfleet_code
and mpm.maint_plan_code = mptm.maint_plan_code
and mpm.carrier_code = in_carrierCode;
LOOP
FETCH vtailAndCheckCur INTO vtailNo, vmaintCheckType;
dbms_output.put_line( vtailNo||' '||vmaintCheckType );
FORECAST_OBJS_LIST(vtailNo,vmaintCheckType,in_WindowPeriodStr,vForecastRecsCursor);
LOOP
forcastRec.EXTEND;
forcastRec(forcastRec.COUNT) := FORECASTOBJECT(null,null,null,null,null,null,null,null,null,null);
dbms_output.put_line( 'test');
FETCH vForecastRecsCursor INTO
forcastRec(forcastRec.COUNT).maintNextPlanCode,
forcastRec(forcastRec.COUNT).tailNumber,
forcastRec(forcastRec.COUNT).maintNextCheckType,
forcastRec(forcastRec.COUNT).maintNextCycleCheckLabel,
forcastRec(forcastRec.COUNT).maintNextStartDate,
forcastRec(forcastRec.COUNT).maintNextEndDate,
forcastRec(forcastRec.COUNT).maintNextDueDate,
forcastRec(forcastRec.COUNT).maintNextCalendarDays,
forcastRec(forcastRec.COUNT).maintForecastFactor,
forcastRec(forcastRec.COUNT).maintCheckColor;
dbms_output.put_line( forcastRec(forcastRec.COUNT).maintNextPlanCode);
EXIT WHEN vForecastRecsCursor%NOTFOUND;
END LOOP;
EXIT WHEN vtailAndCheckCur%NOTFOUND;
END LOOP;
CLOSE vtailAndCheckCur;
OPEN out_forecastRecords FOR
SELECT tailNumber,maintNextCheckType,maintNextPlanCode,maintNextCycleCheckLabel,maintNextStartDate,
maintNextEndDate,maintNextDueDate,maintNextCalendarDays,maintForecastFactor,maintCheckColor
FROM TABLE(CAST(forcastRec AS forecastObjectsList));
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(DBMS_UTILITY.FORMAT_ERROR_STACK);
END FORECAST_MAINTENANCE_SCH;
/
Here if vForecastRecsCursor returns without 0 records in it i am getting ORA-01001: invalid cursor. Anyone please explain how to iterate further by ignoring the error.
Thanks in advance
Try to check if vForecastRecsCursor is opened:
IF vForecastRecsCursor%ISOPEN THEN
...
END IF;
You can control the loop by the GOTO clause or using blocks of code.
DECLARE
dummy_cur SYS_REFCURSOR;
l_dummy_num NUMBER;
CURSOR dual_cur IS
SELECT 1
FROM dual
WHERE 1 = 2;
l_dual_num NUMBER;
l_counter NUMBER := 0;
BEGIN
OPEN dummy_cur FOR SELECT 1 FROM dual;
LOOP
FETCH dummy_cur INTO l_dummy_num;
IF dummy_cur%NOTFOUND THEN
GOTO exit_command;
END IF;
-- inner cursor
BEGIN
-- open inner cursor
IF l_counter = 0 THEN
OPEN dual_cur;
END IF;
-- loop inner cursor
LOOP
FETCH dual_cur INTO l_dual_num;
DBMS_OUTPUT.PUT_LINE('inner loop');
EXIT WHEN dual_cur%NOTFOUND;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('exception');
END;
<<exit_command>>
EXIT WHEN dummy_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('l_dummy_num: ' || l_dummy_num);
l_counter := l_counter + 1;
DBMS_OUTPUT.PUT_LINE('l_counter: ' || l_counter);
END LOOP;
--close inner cursor
CLOSE dual_cur;
CLOSE dummy_cur;
EXCEPTION
WHEN OTHERS THEN
CLOSE dual_cur;
CLOSE dummy_cur;
END;