Oracle Trigger Error : missing left parenthesis - sql

can anyone help me out for this trigger.
CREATE or replace trigger check_limit_to_Y
AFTER INSERT OR UPDATE ON api_user for each row
WHEN EXISTS (SELECT '1' FROM profile b WHERE NEW.mvno_limit!='Y' and b.mvno_id = NEW.mvno_id)
BEGIN
raise_application_error (-20999,'MVNO LIMIT MUST BE SET Y FOR ANY REAL MVNO_ID');
END;
I got the error
Error report -
ORA-00906: missing left parenthesis
00906. 00000 - "missing left parenthesis"
*Cause:
*Action:

This is from the Oracle site: https://docs.oracle.com/cd/E11882_01/appdev.112/e25519/create_trigger.htm#LNPLS01374
WHEN (condition)
Specifies a SQL condition that the database evaluates for each row that the triggering statement affects. If the value of condition is TRUE for an affected row, then tps_body runs for that row; otherwise, tps_body does not run for that row. The triggering statement runs regardless of the value of condition.
The condition can contain correlation names (see referencing_clause ::=). In condition, do not put a colon (:) before the correlation name NEW, OLD, or PARENT (in this context, it is not a placeholder for a bind variable).
See Also:
Oracle Database SQL Language Reference for information about SQL conditions
Restrictions on WHEN (condition)
If you specify this clause, then you must also specify at least one of these timing points:
BEFORE EACH ROW
AFTER EACH ROW
INSTEAD OF EACH ROW
The condition cannot include a subquery or a PL/SQL expression (for example, an invocation of a user-defined function).
Your code doesn't seem to satisfy the last two restrictions (also: the entire condition after the WHEN keyword must be enclosed in parenthesis).
But, you seem to need to use the 'compound trigger syntax' because you want to process both inserts and updates. Check the documentation carefully.
Update: Try this:
CREATE TRIGGER t
BEFORE INSERT OR UPDATE ON api_user FOR EACH ROW
DECLARE CNT integer;
BEGIN
SELECT count(*) into CNT FROM profile b where :NEW.mvno_limit!='Y' and b.mvno_id = :NEW.mvno_id;
IF CNT > 0 THEN
RAISE_APPLICATION_ERROR(-20999,'MVNO LIMIT MUST BE SET Y FOR ANY REAL MVNO_ID');
END IF;
END;

Related

ORACLE 12C - ORA-02287: sequence number not allowed here

I have created sequnce prac_seq:
CREATE SEQUENCE prac_seq
START WITH 300
INCREMENT BY 10;
And I want to use it the following:
UPDATE pracownicy
SET placa_dod = prac_seq.CURRVAL
WHERE id_prac = prac_seq.CURRVAL;
And then I get an error called:
Error report - SQL Error: ORA-02287: sequence number not allowed here
02287. 00000 - "sequence number not allowed here"
*Cause: The specified sequence number (CURRVAL or NEXTVAL) is inappropriate
here in the statement.
*Action: Remove the sequence number.
Why I cannot use sequence like above?
First, the documentation is quite clear on this point:
Restrictions on Sequence Values
You cannot use CURRVAL and NEXTVAL in the following constructs:
The WHERE clause of a SELECT statement
I do understand why NEXTVAL can't be used. You think the WHERE clause is being executed once, but it is (conceptually) executed for each row. Having a side-effecting operation in the WHERE introduces a host of problems. The results of the query using an index, for instance, would be different from the results not using an index.
My guess is that the reason is because both values could change while the query is running, and in some cases, the result of the query is not deterministic.

sql ORA-00900: Invalid SQL statement

please help
IF EXISTS(SELECT * FROM MERC_ADM_VERSION )then UPDATE MERC_ADM_VERSION SET
VER_VALEUR = 20150409 WHERE VER_CLE = 'MEAD' ELSE INSERT INTO MERC_ADM_VERSION
('VER_VALEUR', 'VER_CLE') VALUES (20150409, 'MEAD');
ORA-00900: Invalid SQL statement
Remove the single quotes from the columns in the insert statement.
Instead of
('VER_VALEUR', 'VER_CLE')
It should be
(VER_VALEUR, VER_CLE)
Your question is quite unclear as to what you are trying to do. However, my best interpretation is you are looking for an oracle merge statement. Below is an example based on assumptions I made on the little information you provided. You are most likely looking for a MERGE statement. This allows you to perform a single operation that can either update or insert based on your criteria.
Also, you appear to be using a date, but in number format. I did nothing to address this due to lack of any table definition. You may still have problems with it.
MERGE
INTO merc_adm_version TARGET -- The table you want to update/insert into
USING (SELECT 20150409 as ver_valeur, 'MEAD' as ver_cle FROM dual) SOURCE -- The source of the data
ON (TARGET.ver_cle = SOURCE.ver_cle) -- How to try and match records between source and target
WHEN MATCHED THEN UPDATE SET ver_valeur = 20150409 -- When there is a match, how to update
WHEN NOT MATCHED THEN INSERT (ver_cle, ver_valeur) -- When there is not a match, how to insert
VALUES ('MEAD', 20150409);

Why does DELETE FROM ... FROM ... not error out?

This bit within a stored proc is apparently valid sql:
DELETE TOP (#MaxRecords)
FROM Table
FROM Table B
INNER JOIN Table2 R ON B.fk = R.pk
WHERE R.Value < #DecVariable;
How can two FROM statements be put together and yet still be valid?
First of all TOP in delete syntax indicates that it is SQL Server.
It is perfect valid query, see DELETE:
FROM
An optional keyword that can be used between the DELETE keyword and the target table_or_view_name, or rowset_function_limited.
FROM table_source
Specifies an additional FROM clause. This Transact-SQL extension to DELETE allows specifying data from and deleting the
corresponding rows from the table in the first FROM clause.
This extension, specifying a join, can be used instead of a subquery in the WHERE clause to identify rows to be removed.
DELETE:
Object:

Can I block an insert inside a trigger on Oracle 11g?

So, what I want to do is to block an insert if the condition is met. In this case, I'm developing a simple library database system and I don't want to allow someone to be able to borrow a book if that certain person has already borrowed 2 books and still hasn't returned any of them.
I need to do this via trigger, is it possible? Also, I'd like to know if I can supply a query into the WHEN clause like I did.
CREATE OR REPLACE TRIGGER trigger_borrowing_limit
BEFORE INSERT ON Borrowing
REFERENCING NEW ROW AS NROW
FOR EACH ROW
WHEN SELECT COUNT(*) FROM Borrowing WHERE RETURN_DATE IS NULL AND NROW.ID = Borrowing.ID > 2
BEGIN
?
END
You can't supply a query for the WHEN clause. From the Oracle 11 docs (search for "WHEN (condition)" once you get to the page):
Restrictions on WHEN (condition)
If you specify this clause, then you must also specify FOR EACH ROW.
The condition cannot include a subquery or a PL/SQL expression (for example, an invocation of a user-defined function).
As for preventing the row insert, the comment from Mihai is the way to go. Your front end can catch the exception, and if it's error number -20101 (per Mihai's example) you'll know that the person already has two books out. Note that some drivers will report the absolute value of the exception number, so the error number that reaches you may be 20101.
Addendum: a followup question asked how to apply the "two books out" logic since it's not valid for the WHEN clause.
The answer is to drop the WHEN clause and put the logic into the trigger body. Note that I normally stick with the standard NEW for referencing the new row, so my answer doesn't have the REFERENCING NEW AS NROW:
CREATE OR REPLACE TRIGGER trigger_borrowing_limit
BEFORE INSERT ON Borrowing
DECLARE
booksOut NUMBER;
BEGIN
SELECT COUNT(*) INTO booksOut
FROM Borrowing
WHERE RETURN_DATE IS NULL AND NEW.ID = Borrowing.ID;
IF booksOut > 2 THEN
-- Next line courtesy of Mihai's comment under the question
raise_application_error(-20101, 'You already borrowed 2 books');
END IF;
END;

insert a row into table in pl/pgsql

I am trying to update two tables by inserting some rows into the other. But when I try to do something like this :
BEGIN
FOR id IN (SELECT id FROM table1) LOOP
PERFORM (INSERT INTO anothertable VALUES(id));
END LOOP;
END;
It gives an error I don't know why. syntax error at or near "INTO".
Is it even possible to do such thing without cursors and such updating one by one ?
This is example of bad using PERFORM and bad plpgsql programming style. You must not use a PERFORM there. You should not use a parenthesis there (PL/pgSQL is based on ADA language - not C!). Some correct patterns are:
FOR _id IN
SELECT s.id
FROM sometab s
LOOP
INSERT INTO othertab(id) VALUES(_id);
END LOOP;
or faster (and shorter) pattern
INSERT INTO othertab(id)
SELECT id
FROM other tab
I used a qualified name and prefixes to reduce a risk of conflict between SQL identifiers and PL/pgSQL variables.
Note: PERFORM is implemented as SELECT statement without result processing. So your statement was SELECT (INSERT INTO tab ...) what is unsupported feature now.
why don't you insert it like this:
insert into anothertable
select id from table