Trigger do not compile - oracle

I have a database that is made like this
works_on(ssn,project_number,hours)
and i have a trigger that asks me
that if an emp works more than 50 hours on a project it cannot be put on a 2 project.
if an emp works more than 70 hours on 2 projects it cannot be associated on a 3 project
an emp can only be associated to a max of 6 project
Sorry for my attempt i'm just learning how to make triggers. I have an error near the select statement:
Errore(8,6): PLS-00103: Encountered the symbol "SELECT" when expecting
one of the following: ( - + case mod new not null
continue
avg count current exists max min prior sql stddev sum variance
execute forall merge time timestamp interval date pipe <an alternat
My trigger so far:
create or replace trigger exe
before insert on worsk_on
for each row
declare
too_much_hours EXCEPTION;
no_hours_left EXCEPTION;
too_projects EXCEPTION;
begin
if hours>100
then raise too_much_hours;
end if;
elsif (select count(project_number),ssn,sum(hours) from worsk_on
where count(project_number) > 1 and (sum(hours)>100)
group by ssn,project_number)
then raise no_hours_left;
end if;
else count( porject_number)>6
then raise too_projects;
end if;
EXCEPTION
when too_much_hours then raise_application_error(-20000,'ore progetto sature');
when no_hours_left then raise_application_error(-19000,'ore progetti sature');
when too_projects then raise_application_error(-15151,'ore progetti sature');

There are many errors:
You have not declared a PL/SQL hours variable.
You are using SELECT inside an IF statement.
The SELECT statement does not have an INTO clause.
You are selecting all the ssn and project_number and do not have a filter to correlate it to the row being inserted.
You have spelling mistakes in worsk_on and porject_number.
The third COUNT( project_number ) is not valid as you are not in a SELECT statement.
You have elsif and else statements with no corresponding IF statement (as you have closed the previous statements with END IF.
There may be more (for example, if you fix all of them then I expect you'll get a mutating table exception as you are aggregating over the table you are inserting into.)

Related

Executing the PL/SQL block gives an error which is not understandable

The question given was to write a PL/SQL block to print the details of the customers whose total order quantity is greater than 200 where the Customer table had ID number(5) primary key, Name varchar2(20), Contact_No varchar2(10) and the Order table had Order_Id number(5) primary Key, Quantity number(4) not null, C_id number(5) references Customer(ID).
If no record is found "No Records Found" is to be printed out.
This is the Code I wrote:
SET SERVEROUTPUT ON;
begin
dbms_output.put_line('Customer_Id ' || 'Customer_Name '|| 'Customer_Phone');
for cur_d in (select o.C_ID,total AS sum(o.QUANTITY) from Orders o group by o.C_ID) loop
from Customers c
where c.ID = cur_d.C_ID and cur_d.total > 200;
dbms_output.put_line(c.ID || c.Name || c.Contact_No);
end loop;
end;
/
The error I faced was -
for cur_d in (select o.C_ID,total AS sum(o.QUANTITY) from Orders o group by o.C_ID) loop
ERROR at line 2:
ORA-06550: line 2, column 41:
PL/SQL: ORA-00923: FROM keyword not found where expected
ORA-06550: line 2, column 15:
PL/SQL: SQL Statement ignored
ORA-06550: line 3, column 1:
PLS-00103: Encountered the symbol "FROM" 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'> ')
Even after you correct the substantial that have been pointed out your procedure will still fail. You indicate that if no record is found printing a message to that effect. That in itself is ambiguous. Does that mean for the no records in the data table or no records for a given customer? Either way you have no code to produce such a message. How do you expect it to be written. Finally, SQL is set based processing so you need to start thinking in terms of sets instead of loops. The following reduces the db access to a single query; the loop is only to print results.
begin
dbms_output.put_line('Customer_Id ' || 'Customer_Name '|| 'Customer_Phone' || 'Total Orders');
for cur_d in (
with order_totals as
( select c_id, sum (quantity) order_total
from orders
group by c_id
having sum(quantity) > 200
)
select c.id, c.name, c.contact_no
, case when o.c_id is null
then 'No Records Found'
else to_char(o.order_total)
end order_total
from customers c
left join order_totals o
on c.id = o.c_id
order by c.id
)
loop
dbms_output.put_line(cur_d.ID || cur_d.Name || cur_d.Contact_No || cur_d.order_total);
end loop;
end;
The results are jammed together just as you initially had them. You need to workout their presentation.
There is a "select into" part missing between "for .. loop" and "from" parts. It has to be like this in order to work
for ..... loop
select some_column -- <-- this line is missing
into some_variable -- <-- this line is missing too
from ..........
This is the kind of issue where formatting your code will make the problem obvious. If you always start a new line and indent after for xxx in ( and also place the closing bracket on its own line, and include some gaps between commands, you'll get this, which is clearly wrong:
begin
dbms_output.put_line('Customer_Id ' || 'Customer_Name '|| 'Customer_Phone');
for cur_d in (
select o.c_id, total as sum(o.quantity)
from orders o
group by o.c_id
)
loop
from customers c
where c.id = cur_d.c_id
and cur_d.total > 200;
dbms_output.put_line(c.id || c.name || c.contact_no);
end loop;
end;
The first statement inside the loop seems to be missing something, as ekochergin mentioned.
total as sum(o.quantity) is backwards as Turo mentioned.
If you want id, name and contact_no to be printed in columns, you should look at lpad and rpad for formatting them. Just concatenating them together will produce something unreadable.
The dbms_output inside the loop refers to c.id, c.name and c.contact_no, but the record is called cur_d, not c.
Also cur_d is a slightly confusing name for a record (it's not a cursor). I always use r for cursor records unless there is some other r involved that it could be confused with.

Trigger success with compilation error oracle

I have these tables
PUBRED (cod_pub, title, year, type, medium)
AUTHOR (login, name, surname, institution, country)
AUTHOR_ONE (login, cod_pub)
PUB_CITA (cod_pub, cod_pub_cited)
And I have to get that citations to a publication should always be after it
I have the following trigger but it gives me compilation errors and I don't find any errors looking in other questions
Create or replace trigger works_trg_02
Before insert or update on pub_cita
For each row
Declare
Cnt number;
Begin
Select count (*) into cnt
from pubred pr
inner join pub_cita pc
on :new.pc.cod_pub = pr.cod_pub
inner join pubred pr2
on :new.pc.cod_pub_cited = pr2.cod_pub
where pr.year < pr2.year then 1
Else 0 end = 0;
If cnt <> 0 then
Raise_application_error ('-20001', 'Not possible');
End if;
End works_trg_02;
/
I get the typical error from 'ORA-24344: success with compilation error'
And when doing the inserts to prove it I get 'ORA-04098: trigger 'FIDDLE_WIXYFBGEUZDXILZQBEGR.WORKS_TRG_02' is invalid and failed re-validation'
I have searched other similar questions that have been asked around here adapting my initial solution and I have not been successful and I believe that everything there is is correct.
First, when you get ORA-24344: success with compilation error, you should run show errors, or query the user_errors or all_errors views to find your actual error message.
Second, this is wrong: :new.pc.cod_pub. The :new variable is a record, the row of the table (pub_cita) currently being inserted. You can just say :new.cod_pub.
Third, a trigger can't query its own table - so you can't have pub_cita in your SELECT query. Which is fine, you can refer to it using :new.
Fourth, what is this?
where pr.year < pr2.year then 1
Else 0 end = 0;
I think you started a CASE statement, then deleted part of it? It's not valid syntax.
See if this works for you:
Create or replace trigger works_trg_02
Before insert or update on pub_cita
For each row
Declare
Cnt number;
Begin
Select count (*) into cnt
from pubred pr
inner join pubred pr2
on :new.cod_pub_cited = pr2.cod_pub
where pr.year < pr2.year
and pr.cod_pub = :new.cod_pub
;
If cnt <> 0 then
Raise_application_error ('-20001', 'Not possible');
End if;
End works_trg_02;
/

"ORA-01427 single-row subquery returns more than one row" without having a subquery in procedure

I have a procedure that throws the error "ORA-01427: single-row subquery returns more than one row". When I use the statemt as a simple SELECT I get 1 row per ID.
I researched the ORA-01427, however I couldn't really apply the answers to my error, since from what I understand I don't have a subquery.
CREATE OR REPLACE PROCEDURE CALC_SLOPE (TBL_NAME IN VARCHAR2) AS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE '||TBL_NAME||' ADD (SLOPE_MEDIAN NUMBER(2,2),
SLOPE_75 NUMBER(2,2),
SLOPE_90 NUMBER(2,2))';
EXECUTE IMMEDIATE 'UPDATE '||TBL_NAME||' a1 SET(SLOPE_MEDIAN, SLOPE_75, SLOPE_90)
=(
SELECT ROUND(MEDIAN(b.SLOPE),2) AS SLOPE_MEDIAN,
ROUND(PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY b.slope DESC),2) AS SLOPE_75,
ROUND(PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY b.slope DESC),2) AS SLOPE_90
FROM '||TBL_NAME||' a2,
bbx_slope b
WHERE SDO_CONTAINS(a2.GEOMETRY, b.POINT) = ''TRUE''
GROUP BY a2.ID
)';
END CALC_SLOPE;
Where lies the reason for the error and how can it be fixed?
I am working on WINDOWS 10 on ORACLE 12c Enterprise Edition.
I think you wanted a correlated update
..
FROM '
|| tbl_name || ' a2 JOIN bbx_slope b
ON SDO_CONTAINS(a2.GEOMETRY, b.POINT) = ''TRUE''
WHERE a2.ID = a1.id --This one
GROUP BY a2.ID
..
Right now You trying to update single row:
SET(SLOPE_MEDIAN, SLOPE_75, SLOPE_90)
with your select result. If your SELECT returns 50 rows, this 50 rows ORACLE tries to put into this single row.
Your missing in WHERE clause some conditions on ID column

Getting Unknown Command error on IF-THEN-ELSE

I have the following query that I am using in Oracle 11g
IF EXISTS (SELECT * FROM EMPLOYEE_MASTER WHERE EMPID='ABCD32643')
THEN
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1' where EMPID='ABCD32643' ;
ELSE
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE) values('A62352','JOHN DOE','1') ;
END IF;
On running the statement I get the following output:
Error starting at line : 4 in command -
ELSE
Error report -
Unknown Command
1 row inserted.
Error starting at line : 6 in command -
END IF
Error report -
Unknown Command
The values get inserted with error when I run it directly. But when I try to execute this query through my application I get an oracle exception because of the error generated :
ORA-00900: invalid SQL statement
And hence the values are not inserted.
I am relatively new to Oracle. Please advise on what's wrong with the above query so that I could run this query error free.
If MERGE doesn't work for you, try the following:
begin
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1'
where EMPID='ABCD32643' ;
if SQL%ROWCOUNT=0 then
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE)
values('A62352','JOHN DOE','1') ;
end if;
end;
Here you you the update on spec, then check whether or not you found a matching row, and insert in case you didn't.
"what's wrong with the above query "
What's wrong with the query is that it is not a query (SQL). It should be a program snippet (PL/SQL) but it isn't written as PL/SQL block, framed by BEGIN and END; keywords.
But turning it into an anonymous PL/SQL block won't help. Oracle PL/SQL does not support IF EXISTS (select ... syntax.
Fortunately Oracle SQL does support MERGE statement which does the same thing as your code, with less typing.
merge into EMPLOYEE_MASTER em
using ( select 'A62352' as empid,
'JOHN DOE' as empname,
'1' as emptype
from dual ) q
on (q.empid = em.empid)
when not matched then
insert (EMPID,EMPNAME,EMPTYPE)
values (q.empid, q.empname, q.emptype)
when matched then
update
set em.empname = q.empname, em.emptype = q.emptype
/
Except that you're trying to update empid as well. That's not supported in MERGE. Why would you want to change the primary key?
"Does this query need me to add values to all columns in the table? "
The INSERT can have all the columns in the table. The UPDATE cannot change the columns used in the ON clause (usually the primary key) because that's a limitation of the way MERGE works. I think it's the same key preservation mechanism we see when updating views. Find out more.

Why I'm getting the ORA-01003: no statement parsed error?

Why am I getting this error and what does it mean by no statement parsed.
ORA-01003: no statement parsed
Here is the code:
PROCEDURE ORIGINAL_TABLE.UPDATE_GROUPS IS
-- cursor loaded with the swam groups
CURSOR cursor1 IS
SELECT ID, NEW_DESCRIPTION
FROM NEW_TABLE.NEW_GROUP_TABLE#DB_LINK.X;
BEGIN
FOR C1_REC IN cursor1 LOOP
UPDATE
ORIGINAL_TABLE."GROUPS"
SET
GROUP_ID = C1_REC.ID
WHERE
ORIGINAL_TABLE."GROUPS".DESCRIPTION = C1_REC.NEW_DESCRIPTION;
IF (SQL%ROWCOUNT = 0) THEN
INSERT INTO
ORIGINAL_TABLE.GROUPS("GROUP_ID", "DESCRIPTION")
VALUES (C1_REC.ID, C1_REC.NEW_DESCRIPTION);
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END;
What I try to do with the code above is to update and old table with the values from a new table and in case that the new group doesn't exist insert it.
Update: Changed %ROWCOUNT > 0 for %ROWCOUNT = 0
Use MERGE statement, it does update/insert stuff more efficiently and pay attention your plsql doesn't provide it is intended for. It tries to make an update statement and if a record found it inserts another record. In order to fix it use
IF (SQL%ROWCOUNT = 0)
I presume the reason of the issue is the . in DBLINK name.
Moreover I would suggest to get rid of quotes for tables/fields just in case as well as schema name.
Another words delete all ORIGINAL_TABLE.
merge into groups g
using (
SELECT ID, NEW_DESCRIPTION
FROM NEW_TABLE.NEW_GROUP_TABLE#DB_LINK.X
) nt
on (nt.NEW_DESCRIPTION = g.description )
when matched then update set g.group_id = nt.id
when non matched then insert(GROUP_ID, DESCRIPTION)
values(nt.id, nt.NEW_DESCRIPTION)

Resources