Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I'm using PL/SQL developer to créate this trigger, I read somewhere that it could be a CR-LF missinterpretation by Oracle, but it is the first time this occurs. Below the code is the Error log:
create or replace trigger Terreno_nomenc
before update of circ_prov,sector_prov,cod_div_prov,nro_div_prov,nro_parc_prov on adminmo.terreno
for each row
declare
circ integer:= 0;
sector integer:= 0;
cod_div integer:= 0;
nro_div integer:= 0;
nro_par integer:= 0;
nueva_nomenc varchar2(18) := ' ';
vieja_nomenc varchar2(18) := ' ';
dominio integer:= 0;
begin
vieja_nomenc:= :old.nomenc;
if (:new.circ_prov <> :old.circ_prov) then {
circ := :new.circ_prov;
}
else {
circ := :old.circ_prov;
}
end if;
if(:new.sector_prov <> :old.sector_prov) then {
sector := :new.sector_prov;
}
else {
sector := :old.sector_prov;
}
end if;
if(:new.cod_div_prov <> :old.cod_div_prov) then {
cod_div := :new.cod_div_prov;
}
else{
cod_div := :old.cod_div_prov;
}
end if;
if(:new.nro_div_prov <> :old.nro_div_prov) then {
nro_div := :new.nro_div_prov;
}
else{
nro_div := :old.nro_div_prov;
}
end if;
if(:new.nro_parc_prov <> :old.nro_parc_prov) then {
nro_par := :new.nro_parc_prov;
}
else{
nro_par := :old.nro_parc_prov;
}
end if;
if(circ > 0 and sector > 0 and cod_div > 0 and nro_div > 0) {
nueva_nomenc := to_char(circ,'999') || '-' || to_char(sector,'99') || '-' || to_char(cod_div,'99') || '-' || to_char(nro_div,'9999') || '-' || to_char(nro_par, '999');
select t.refnro into dominio
from geoimax.comodoro_ejido_dom_ref t
where t.reftex = vieja_nomenc;
update terreno set nomenc = nueva_nomenc where terreno.subsistema = :new.subsistema and terreno.partida = :new.partida;
update geoimax.Comodoro_Ejido_Dom_Ref c set c.reftex = nueva_nomenc where c.refnro = dominio;
}
end if;
end Terreno_nomenc;
Error: PLS-00103: Encountered the symbol "{" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
The symbol "begin was inserted before "{" to continue.
Line: 19
Text: if (:new.circ_prov <> :old.circ_prov) then {
Error: PLS-00103: Encountered the symbol "}" when expecting one of the following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted delimited-identifier>
<a bind variable> << continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall
merge pipe purge
Line: 21
Text: }
You don't use curly brackets in PL/SQL. None of the { or } characters in your code are needed and all of them are syntax errors. You'll need to remove all those characters.
Once you do that, you may still get syntax errors (since you didn't post your table definitions, we have no way to try to fix the trigger and verify that it compiles on our system). But they'll at least be different errors.
On closer inspection, you also appear to have an UPDATE statement in the trigger that is trying to update rows in the table that the row-level trigger is defined on. The trigger is trying to update terreno and is defined on a table terreno (unless you have two tables with the same name in different schemas and you are being very tricky with name resolution). That's going to throw a mutating table error when you try to run it. Are you actually trying to modify the current row that is being updated? Or are you trying to update other rows in the table? If the latter, that strongly implies that the data model is incorrect because that implies that data in one row depends on data in other rows of the same table which violates basic normalization.
If you are merely trying to modify data in the current row, don't use an UPDATE. Simply modify the :new pseudorecord.
:new.nomenc := nueva_nomenc;
Couple of errors:
{} curly braces should be removed.
THEN missed out in one of the IF statements.
CREATE OR replace TRIGGER terreno_nomenc
BEFORE UPDATE OF circ_prov, sector_prov, cod_div_prov, nro_div_prov,
nro_parc_prov ON adminmo.terreno
FOR EACH ROW
DECLARE
circ INTEGER := 0;
sector INTEGER := 0;
cod_div INTEGER := 0;
nro_div INTEGER := 0;
nro_par INTEGER := 0;
nueva_nomenc VARCHAR2 ( 18 ) := ' ';
vieja_nomenc VARCHAR2 ( 18 ) := ' ';
dominio INTEGER := 0;
BEGIN
vieja_nomenc := :OLD.nomenc;
IF ( :NEW.circ_prov <> :OLD.circ_prov ) THEN
circ := :NEW.circ_prov;
ELSE
circ := :OLD.circ_prov;
END IF;
IF ( :NEW.sector_prov <> :OLD.sector_prov ) THEN
sector := :NEW.sector_prov;
ELSE
sector := :OLD.sector_prov;
END IF;
IF ( :NEW.cod_div_prov <> :OLD.cod_div_prov ) THEN
cod_div := :NEW.cod_div_prov;
ELSE
cod_div := :OLD.cod_div_prov;
END IF;
IF ( :NEW.nro_div_prov <> :OLD.nro_div_prov ) THEN
nro_div := :NEW.nro_div_prov;
ELSE
nro_div := :OLD.nro_div_prov;
END IF;
IF ( :NEW.nro_parc_prov <> :OLD.nro_parc_prov ) THEN
nro_par := :NEW.nro_parc_prov;
ELSE
nro_par := :OLD.nro_parc_prov;
END IF;
IF ( circ > 0
AND sector > 0
AND cod_div > 0
AND nro_div > 0 ) THEN
nueva_nomenc := To_char (circ, '999')
|| '-'
|| To_char (sector, '99')
|| '-'
|| To_char (cod_div, '99')
|| '-'
|| To_char (nro_div, '9999')
|| '-'
|| To_char (nro_par, '999');
SELECT T.refnro
INTO dominio
FROM geoimax.comodoro_ejido_dom_ref T
WHERE T.reftex = vieja_nomenc;
UPDATE terreno
SET nomenc = nueva_nomenc
WHERE terreno.subsistema = :NEW.subsistema
AND terreno.partida = :NEW.partida;
UPDATE geoimax.comodoro_ejido_dom_ref C
SET C.reftex = nueva_nomenc
WHERE C.refnro = dominio;
END IF;
END terreno_nomenc;
/
Related
I'm trying to run a PL/SQL Script I made but I'm getting an error:
PLS-00653: aggregate/table functions are not allowed in PL/SQL scope
The problem here is not the error in itself but the line where it's being thrown from.
Here's my PL/SQL block which throws this error:
DECLARE
TYPE l_code_arr_typ IS VARRAY(3) OF VARCHAR2(100);
l_code_arr l_code_arr_typ;
l_objet objet_interface_pkg.objet_interface_typ;
l_resultat CLOB;
l_valeur valeur_pkg.valeur_typ;
l_liens lien_objet_interface_pkg.lien_objet_interface_tab;
l_rows NUMBER;
BEGIN
l_code_arr := l_code_arr_typ('champ.fonctions.dossier.particulier',
'champ.fonctions.region.admin',
'champ.fonctions.ministere.organisme');
l_resultat := '{';
FOR l_idx IN 1 .. l_code_arr.count LOOP
l_objet := objet_interface_pkg.obtenir_fnc(p_code => l_code_arr(l_idx),
p_acron_sys => :acronyme);
l_resultat := l_resultat || '"' || l_objet.code || '":[';
l_liens := lien_objet_interface_pkg.obtenir_par_objet_fnc(p_id_objet => l_objet.id_obj);
FOR l_lien IN (SELECT * FROM TABLE(l_liens)) LOOP
l_valeur := valeur_pkg.obtenir_fnc(p_id => l_lien.id_valeur);
l_resultat := l_resultat || '"' || l_valeur.valeur || '"';
FOR l_enfant IN (SELECT *
FROM TABLE(valeur_pkg.obtenir_enfants_fnc(p_id_parent => l_lien.id_valeur,
p_code => l_valeur.valeur))) LOOP
l_resultat := l_resultat || ',"' || l_enfant.valeur || '"';
END LOOP;
END LOOP;
l_resultat := l_resultat || '],';
END LOOP;
<<<<<<<<<< ERROR THROWN HERE (EMPTY LINE)
l_resultat := substr(l_resultat, 1, length(l_resultat) - 1) || '}';
dbms_output.put_line(l_resultat);
END;
The error throws on 34:17 (line:column) which is the fourth line from the end of the code block. As you can see the real problem is that this line is an empty line. Moreover, none of the lines near that empty line contains a call to an aggregate function. So where's the aggregate/table function's call located?
I'm wondering if the problem really comes from my code or if my PL/SQL Developer is broken.
I hope someone can help me...
I found the solution!
The problem is that the function lien_objet_interface_pkg.obtenir_par_objet is PIPELINED and a pipelined return cannot be stored in a variable.
So these 2 lines...
l_liens := lien_objet_interface_pkg.obtenir_par_objet_fnc(p_id_objet => l_objet.id_obj);
FOR l_lien IN (SELECT * FROM TABLE(l_liens)) LOOP
...need to be merge into one single line like so:
FOR l_lien IN (SELECT * FROM TABLE(lien_objet_interface_pkg.obtenir_par_objet_fnc(p_id_objet => l_objet.id_obj))) LOOP
However, I still don't know why PL\SQL Developer said my error comes from line 34 and It'll probably remain a mystery. If anyone have answer to this mystery, please feel free to let me know.
I'm stuck on this block of statements and don't know how to program the output when the code runs to show the amount of the payment as $10.00 and the balance remaining in the same format. My code also prompts me twice for idpledge... I've got some markup in the code for topics I don't quite understand. Using Oracle 11g 2e and the book isn't very helpful. If there is a recommendation for beginner books or resources I am listening (reading). Code is below:
SET SERVEROUTPUT ON;
DECLARE
pay_num NUMBER(2) := 0; /*initialize to 0 */
loop_count NUMBER(2) := 12; /*intialize to max number of months */
pay_amt NUMBER(8,2);
pledge_bal NUMBER(8,2);
v_pledgeamt NUMBER(8,2);
start_date DATE := '04-OCT-2012';
due_date DATE;
v_due_date VARCHAR2(15);
BEGIN
SELECT pledgeamt INTO v_pledgeamt
FROM DD_PLEDGE
WHERE idpledge=&idpledge;
pay_amt := (v_pledgeamt / loop_count);
due_date := start_date;
pledge_bal := (v_pledgeamt - pay_amt);
FOR i IN 1..loop_count LOOP
pay_num := pay_num + 1;
v_due_date := TO_CHAR(due_date, 'MM-DD-YYYY');
due_date := add_months(due_date, 1);
pledge_bal := (pledge_bal - pay_amt);
DBMS_OUTPUT.PUT_LINE (
'Payment Num: ' || pay_num
|| ' ' || 'Due Date: ' || v_due_date
|| ' ' || 'Amount Due: ' || pay_amt
|| ' ' || 'Balance: ' || TO_CHAR(pledge_bal, '$')); /* how to format with $*/
END LOOP;
END;
As mentioned at Docs you can use the to_char with a proper formatter. In your case it would be to_char(pledge_bal, '$9,999.99')
Using the format as '$9,999.99' fulfills the following objectives :
Returns a comma in the specified position. You can specify multiple commas in a number format model.
Returns a decimal point, which is a period (.) in the specified position.
Returns value with a leading dollar sign.
If required you can check for more parameters at the link mentioned.
I have a procedure where I am checking whether there are new codes. If there are then insert them into a table. And also save the new data into a csv or txt file and email them to me.
I can't get the logic for how to redirect the new data to file or just even put the data as simple text in the email. Thanks
create or replace
PROCEDURE new_codes_test( today_date IN VARCHAR2 DEFAULT NULL, v_proc_return OUT NUMBER) AS
sql_str VARCHAR2(4000);
.....
BEGIN
v_start_time := SYSDATE;
v_proc_return := 0;
....
INSERT INTO NEW_CODES_test
SELECT DISTINCT Sy_ID ,P_CODE, SYSDATE
FROM X.B
WHERE NOT EXISTS (SELECT DISTINCT Sy_ID, P_CODE
FROM X.C
WHERE today = today_date) ;
COMMIT;
--SELECT ___ into ___ from X.B;
sql_str := 'UTL_MAIL.send(sender => ''
,recipients => ''
,cc => ''
,subject => 'New codes'
,MESSAGE => '' )';
--EXECUTE IMMEDIATE sql_str;
p_proc_return := v_proc_return;
EXCEPTIONS
....
END;
To write to a file the UTL_FILE package will come in handy. To write an email you'll need to put the text to be sent into some sort of string before passing it to the MESSAGE argument of UTL_MAIL.SEND. You'll also need to be sure UTL_MAIL is installed and set up on your server; see this FAQ.
So something like the following may be useful:
CREATE OR REPLACE FUNCTION NEW_CODES_TEST(today_date IN VARCHAR2)
RETURN NUMBER
AS
strMessage VARCHAR2(32767);
nRows NUMBER := 0;
fHandle UTL_FILE.FILE_TYPE;
BEGIN
v_start_time := SYSDATE;
fHandle := UTL_FILE.FOPEN(someDirectory, someFilename, 'w');
FOR aRow IN (SELECT DISTINCT SY_ID ,P_CODE
FROM X.B
WHERE NOT EXISTS (SELECT DISTINCT Sy_ID, P_CODE
FROM X.C
WHERE today = today_date)
LOOP
INSERT INTO NEW_CODES_test
VALUES (aRow.SY_ID, aRow.P_CODE, SYSDATE);
UTL_FILE.PUT_LINE(fHandle, aRow.SY_ID || ', ' || aRow.P_CODE);
strMessage := strMessage || 'Added ' || aRow.SY_ID || ', ' ||
aRow.P_CODE || CHR(10);
nRows := nRows + 1;
END LOOP;
COMMIT;
UTL_FILE.FCLOSE(fHandle);
UTL_MAIL.SEND(sender => 'me#mycompany.com',
recipients => 'you#someplaceelse.net',
subject => 'New codes',
message => strMessage);
RETURN 0;
EXCEPTIONS
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
RETURN SQLCODE;
END NEW_CODES_TEST;
Share and enjoy.
-- File: PLh10.sql
-- Author: John Tunisi
-- ----------------------------------
SET SERVEROUTPUT ON
SET VERIFY OFF
-- ----------------------------------
ACCEPT traineeID NUMBER PROMPT 'Enter a trainee ID: '
ACCEPT increment NUMBER PROMPT 'Enter an increment for his trainers: '
DECLARE
sr sailors%ROWTYPE;
CURSOR tCursor IS
SELECT S.sid, S.sname, S.rating, S.age, S.trainee
FROM sailors S, sailors R
WHERE R.sid = '&traineeID' AND
S.trainee = R.sid;
BEGIN
OPEN tCursor;
LOOP
-- Fetch the qualifying rows one by one
FETCH tCursor INTO sr;
-- Print the sailor' old record
DBMS_OTPUT.PUT_LINE ('+++++ old row: '||sr.sid||' '
||sr.sname||sr.rating||' '||sr.age||' '||sr.trainee);
-- Increment the trainers' rating
sr.rating := sr.rating + &increment;
UPDATE sailors
SET rating = sr.rating
WHERE sailors.sid = sr.sid;
-- Print the sailor' new record
DBMS_OUTPUT.PUT_LINE ('+++++ new row: '||sr.sid||' '
||sr.sname||sr.rating||' '||sr.age||' '||sr.trainee);
END LOOP;
IF tCursor%ROWCOUNT = 0 /*test whether the trainee has no trainers*/
DBMS_OUTPUT.PUT_LINE ('+++++ '||sr.sid||' is either not a sailor,'
||' or has no trainer');
ELSE
DBMS_OUTPUT.PUT_LINE ('+++++ DB has been updated');
END IF;
CLOSE tCursor;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('+++++'||SQLCODE||'...'||SQLERRM);
END;
/
-- Let's see what happened to the database
SELECT *
FROM sailors S
WHERE S.trainee = '&traineeID';
UNDEFINE traineeID
UNDEFINE increment
Okay, so I need to increment trainers based on a trainee. I think most of it is correct, but I am getting an error on the line below " DBMS_OUTPUT.PUT_LINE ('+++++ '||sr.sid||' is either not a sailor,'". I am not sure what is supposed to go here, as this is my first time writing PL/SQL.
Try this:
SET SERVEROUTPUT ON
SET VERIFY OFF
-- ----------------------------------
ACCEPT traineeID NUMBER PROMPT 'Enter a trainee ID: '
ACCEPT increment NUMBER PROMPT 'Enter an increment for his trainers: '
DECLARE
sr sailors%ROWTYPE;
srNew sailors%ROWTYPE;
nRecords_updated NUMBER := 0;
CURSOR tCursor IS
SELECT S.sid, S.sname, S.rating, S.age, S.trainee
FROM sailors S, sailors R
WHERE R.sid = '&traineeID' AND
S.trainee = R.sid;
BEGIN
OPEN tCursor;
LOOP
-- Fetch the qualifying rows one by one
FETCH tCursor INTO sr;
EXIT WHEN tCursor%NOTFOUND; -- ADDED
-- Print the sailor' old record
DBMS_OUTPUT.PUT_LINE ('+++++ old row: ' || sr.sid || ' ' ||
sr.sname || sr.rating || ' ' || sr.age ||
' ' || sr.trainee);
-- Increment the trainers' rating
sr.rating := sr.rating + &increment;
UPDATE sailors
SET rating = sr.rating
WHERE sailors.sid = sr.sid;
nRecords_updated := nRecords_updated + SQL%ROWCOUNT; -- ADDED
-- Obtain the updated record -- ADDED
SELECT s.* -- ADDED
INTO srNew -- ADDED
FROM SAILORS s -- ADDED
WHERE s.SID = sr.SID; -- ADDED
-- Print the sailor' new record
DBMS_OUTPUT.PUT_LINE ('+++++ new row: ' || srNew.sid || ' ' || -- CHANGED
srNew.sname || srNew.rating || ' ' || -- CHANGED
srNew.age || ' ' || srNew.trainee); -- CHANGED
END LOOP;
IF nRecords_updated = 0 /*test whether the trainee has no trainers*/ -- CHANGED
DBMS_OUTPUT.PUT_LINE ('+++++ ' || sr.sid || ' is either not a sailor,' ||
' or has no trainer');
ELSE
DBMS_OUTPUT.PUT_LINE ('+++++ DB has been updated');
END IF;
CLOSE tCursor;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('+++++'||SQLCODE||'...'||SQLERRM);
END;
/
I included comments (either ADDED or CHANGED) on the lines I altered or added. It's tough to say whether this will work or not as I don't have access to your data but it might be a step in the right direction.
Share and enjoy.
I have problem with mu procedure which insert duplicate last record in table
example when I put INSERT..... 'AAA' I got to rows in table 'AAA' and 'AAA'
In place when I put DBMS()... in code I got tow records
I use trigger and sequence for column ID in HistoriaDismissDate but they are in good condition. I check if I dropped trigger and sequence and its the same situation
I also use viewDate but this view get mi ONE record not two
my code
CREATE OR REPLACE PROCEDURE ChangeDismissDate
IS
v_id VARCHAR2(11);
v_dateBhd DATE := TO_DATE('20491231','yyyymmdd');
v_dateDismiss DATE := TO_DATE('20491231','yyyymmdd');
v_login VARCHAR2(50);
last_id NUMBER :=0;
CURSOR cur IS
select EMP_NO, LOGIN, ODEJSCIE_BHD, ODEJSCIE_OLD FROM viewDate;
BEGIN
OPEN cur;
LOOP
FETCH cur INTO v_id,v_login,v_dateBhd,v_dateDismiss;
DBMS_OUTPUT.put_line(v_id || ' ' || v_login || ' ' || v_dateBhd || ' ' || v_dateDismiss);
UPDATE employee_tab SET DISMISS_DATE = v_dateBhd WHERE EMP_NO = v_id;
COMMIT;
INSERT INTO HistoriaDismissDate(CUSTOMER_ID,LOGIN, DATE_CHANGE, DATE_BHD, DATE_DISMISS)
VALUES(v_id,v_login, sysdate, v_dateBhd, v_dateDismiss);
COMMIT;
EXIT WHEN cur%NOTFOUND;
END LOOP;
CLOSE cur;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;
/
2 tips on your original code:
1) cursor is a very old programming technic on PL/SQL. Prefer to use FOR ... LOOP construction. It's cleaner and less error-prone! See how it works:
CREATE OR REPLACE PROCEDURE ChangeDismissDate IS
BEGIN
for cur in (select EMP_NO, LOGIN, ODEJSCIE_BHD, ODEJSCIE_OLD FROM viewDate) loop
DBMS_OUTPUT.put_line(cur.EMP_NO || ' ' || cur.login || ' ' || cur.ODEJSCIE_BHD || ' ' || cur.ODEJSCIE_OLD);
UPDATE employee_tab
SET DISMISS_DATE = cur.ODEJSCIE_BHD
WHERE EMP_NO = cur.EMP_NO;
INSERT INTO HistoriaDismissDate
( CUSTOMER_ID,LOGIN, DATE_CHANGE, DATE_BHD, DATE_DISMISS )
VALUES
( cur.EMP_NO, cur.LOGIN, sysdate, cur.ODEJSCIE_BHD, cur.ODEJSCIE_OLD, );
end loop;
end;
/
2) Never, I mean never put a commit inside your procedure. The commit should be done on the caller block or on your client-side app. When you put a commit inside your procedure, you miss the chance to rollback after running it and other procedures could not call it if they want to control the transaction flow.