CREATE TRIGGER Comparer_Prix
BEFORE UPDATE ON ARTICLE
FOR EACH ROW BEGIN
SELECT ARTICLE.PRIXVENTE, ARTICLE.N_PRODUIT, ARTICLE.N_FABRICANT, LIEN_FABRICANT_PRODUIT.PRIXFABRICANT, LIEN_FABRICANT_PRODUIT.N_PRODUIT, LIEN_FABRICANT_PRODUIT.N_FABRICANT
FROM ARTICLE, LIEN_FABRICANT_PRODUIT
WHERE ARTICLE.N_FABRICANT=LIEN_FABRICANT_PRODUIT.N_FABRICANT AND ARTICLE.N_PRODUIT=LIEN_FABRICANT_PRODUIT.N_PRODUIT;
IF (NEW.PRIXVENTE< PRIXFABRICANT) THEN RAISE_APPLICATION_ERROR(-20001, 'Refusé');
END IF;
END;
I am trying to create a trigger that codes the following rule: the sales price must always be higher than the manufacturing price.
Here the errors I get:
Error(2,3): PL/SQL: SQL Statement ignored
Error(2,69): PL/SQL: ORA-00904: "LIEN_FABRICANT_PRODUIT"."PRIXFABRICANT" : invalid identifier
Error(2.92): PLS-00302: The component "PRIXFABRICANT" must be declared.
Error(5,3): PL/SQL: Statement ignored
Error(5,10): PLS-00201: the identifier 'NEW.PRIXVENTE' must be declared.
It is not new, but :new (you're missing a colon).
Though, that's not the only issue here; you can't select from a table which is just being modified; mutating table error is expected. Lucky you, you don't have to select from article as you can reference its values using the same :new value.
ORA-00904 means that you've used a column name which doesn't exist in that table. As you didn't post tables' descriptions, I'm simply repeating what you wrote. Fix it yourself.
Something like this:
create or replace trigger comparer_prix
before update on article
for each row
declare
l_prixfabricant lien_fabricant_produit.prixfabricant%type;
begin
select prixfabricant
into l_prixfabricant
from lien_fabricant_produit
where n_fabricatn = :new.n_fabricant
and n_produit = :new.n_produit;
if :new.prixvente < l_prixfabricant then
raise_application_error(-20001, 'Refusé');
end if;
end;
/
Also, it wouldn't harm if you learnt how to properly format code and make it easier to read. Use table aliases (instead of those lengthy table names).
If You compare two tables use:
... WHERE ... AND EXISTS(SELECT * FROM <TAB_COMPARE>)
Related
I'm taking my first steps in Pl/SQL and am struggling with triggers. I've tried creating the trigger below but am receiving this error:
Error at line 2: PL/SQL: SQL Statement ignored
PL/SQL: ORA-00942: table or view does not exist
To clarify: I have checked the name of the table over and over, and it does exist. It is also in the same schema as the trigger I'm trying to create. The 'customer_seq.NEXTVAL' refers to a sequence created previously that runs without errors.
The code is as follows:
CREATE TRIGGER new_customer
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
INSERT INTO customer_id VALUES ('c-', customer_seq.NEXTVAL);
END;
Thanks in advance for any help.
You probably intend something like this:
CREATE TRIGGER new_customer
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
SELECT customer_seq.NEXTVAL INTO :NEW.customer_id
FROM dual;
END;
It is unclear what the purpose of 'C_' is. If it is part of the customer id, I would advise you to stick to numbers.
Also note that more recent versions of Oracle support generated always as identity -- which is much preferred over defining a sequence and trigger.
create or replace function idxF(status IN char) return char deterministic is
retVal CHAR(1);
begin
dbms_output.put_line('P');
retVal:=CASE status
when 'P' then 'P'
when 'H' then 'H'
else null
end ;
return retVal;
end idxF;
create index setIndexOnStatus on ORDER(idXF(STATUS));
SQL Error: ORA-00904: "IDXF": invalid identifier
STATUS is a CHAR(1) column in ORDER table.
Why is the compiler saying that IDXF is an invalid identifier?
ORDER is a reserved word in Oracle (part of ORDER BY clause) so you shouldn't use it as a name for your table.
Technically, you can escape a reserved word with double quotes:
create index setIndexOnStatus on "ORDER"(idXF(STATUS));
Probably, this table was created like this in a first place.
This approach is extremely problematic because you'll need to escape every query to this table and it's not always possible, especially with auto-generated queries.
So, don't go this way, rename the table instead.
P.S. I couldn't reproduce ORA-00904 on this query. Invalid table name leads to ORA-00903: invalid table name. Escaped query works fine for me. If you still have ORA-00904 error then you'll need to build a reproducible example to demonstrate your problem (i.e. include CREATE TABLE statement and specify the Oracle version).
I want to create a table random_record that takes in the same columns as another table simulated_records; one of the columns is grade. But I keep getting this error:
ERROR: "random_record.grade" is not a known variable
LINE 45: random_record.grade = c_grade;
^
********** Error **********
ERROR: "random_record.grade" is not a known variable
SQL state: 42601
Character: 1635
FOR i IN 1..6 LOOP
CREATE TABLE random_record AS
SELECT ....
IF random_record.grade = '-' THEN
.....
END IF;
....
END LOOP;
I am not sure if I am properly creating the table.
you created table well, but the table is not a variable, so line
IF random_record.grade = '-' THEN
has not any sense. It is hard to identify, what you want, because using table in this context has not any value.
creating in table in cycle has another issue - the statement CREATE TABLE will work only in first loop of cycle. Second loop has to fail, because table exists already.
It is hard help, because this code is messy - it is mixing variables, tables together, and it is not possible. Every object has own dimension, own access methods, and these mechanisms are different.
I'm new in oracle and i don't know what is wrong with this trigger:
CREATE OR REPLACE TRIGGER "propuesta_casas"
BEFORE INSERT ON "PROPUESTA_TIENDA_BARRIO"
FOR EACH ROW
WHEN (new."CASASCAL" IS NULL)
BEGIN
SELECT PROPUESTA.CASAS
INTO :new."CASASCAL"
FROM PROPUESTA WHERE PROPUESTA.IDPROPUESTA=new.IDPROPUESTA ;
END;
/
Error:
PL/SQL: ORA-00904: "NEW"."IDPROPUESTA": identifider not valid
Not sure why the accepted answer has been accepted as neither it nor the attached comments seem to address the obvious issue in the posted code.
In a trigger body we reference values in the inserted row with the :NEW code word. The posted code lacks the colon when it references the column in the WHERE clause. This is what is needed:
CREATE OR REPLACE TRIGGER "propuesta_casas"
BEFORE INSERT ON "PROPUESTA_TIENDA_BARRIO"
FOR EACH ROW
WHEN (new."CASASCAL" IS NULL)
BEGIN
SELECT PROPUESTA.CASAS
INTO :new."CASASCAL"
FROM PROPUESTA
WHERE PROPUESTA.IDPROPUESTA=:new.IDPROPUESTA ;
END;
/
Incidentally, watch out for using lower case in double quotes when creating objects.
By default all Oracle names are stored in the data dictionary in upper case, but the SQL statements are case insensitive. So the following two statments refer to the same object:
select * from emp
/
select * from EMP
/
However, if we create our object with a name in mixed case or lower case and put it in double quotes it is stored in the data dictionary with that exact case. This means we have to use that exact case whenever we reference the object, in double quotes. So if we created a table with all lower case ...
create table "emp" ...
... then this statement will fail:
select * from emp
/
It has to be
select * from "emp"
/
Of course if we already have a table called EMP then the first statement would have succeeded, if would just have selected from a different table.
In the case of triggers we generally don't refer to them by name. But we have to use the case whenever we look up the trigger in the data dictionary:
select status
from user_triggers
where trigger_name = 'propuesta_casas'
/
From what you described:
Try to recompile the trigger and see what happens...
A trigger becomes invalid if the base object (ex..table) becomes invalid or altered and the trigger refers to the affected table.
Excuting the line of SQL:
SELECT *
INTO assignment_20081120
FROM assignment ;
against a database in oracle to back up a table called assignment gives me the following ORACLE error:
ORA-00905: Missing keyword
Unless there is a single row in the ASSIGNMENT table and ASSIGNMENT_20081120 is a local PL/SQL variable of type ASSIGNMENT%ROWTYPE, this is not what you want.
Assuming you are trying to create a new table and copy the existing data to that new table
CREATE TABLE assignment_20081120
AS
SELECT *
FROM assignment
First, I thought:
"...In Microsoft SQL Server the
SELECT...INTO automatically creates
the new table whereas Oracle seems to
require you to manually create it
before executing the SELECT...INTO
statement..."
But after manually generating a table, it still did not work, still showing the "missing keyword" error.
So I gave up this time and solved it by first manually creating the table, then using the "classic" SELECT statement:
INSERT INTO assignment_20081120 SELECT * FROM assignment;
Which worked as expected. If anyone come up with an explanaition on how to use the SELECT...INTO in a correct way, I would be happy!
You can use select into inside of a PLSQL block such as below.
Declare
l_variable assignment%rowtype
begin
select *
into l_variable
from assignment;
exception
when no_data_found then
dbms_output.put_line('No record avialable')
when too_many_rows then
dbms_output.put_line('Too many rows')
end;
This code will only work when there is exactly 1 row in assignment. Usually you will use this kind of code to select a specific row identified by a key number.
Declare
l_variable assignment%rowtype
begin
select *
into l_variable
from assignment
where ID=<my id number>;
exception
when no_data_found then
dbms_output.put_line('No record avialable')
when too_many_rows then
dbms_output.put_line('Too many rows')
end;
Though this is not directly related to the OP's exact question but I just found out that using a Oracle reserved word in your query (in my case the alias IN) can cause the same error.
Example:
SELECT * FROM TBL_INDEPENTS IN
JOIN TBL_VOTERS VO on IN.VOTERID = VO.VOTERID
Or if its in the query itself as a field name
SELECT ..., ...., IN, ..., .... FROM SOMETABLE
That would also throw that error. I hope this helps someone.
If you backup a table in Oracle Database. You try the statement below.
CREATE TABLE name_table_bk
AS
SELECT *
FROM name_table;
I am using Oracle Database 12c.
Late answer, but I just came on this list today!
CREATE TABLE assignment_20101120 AS SELECT * FROM assignment;
Does the same.