pl/pgsql - How to create a table from another table - sql

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.

Related

How to compare two values in different tables with a TRIGGER SQL?

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>)

"SELECT something INTO variable" in trigger function's code creates a table named variable

I discovered a mysterious table named num in my database which has one column named count. I had no idea how it got there, then I realized it might be caused by a misbehaving trigger.
I have a trigger function:
DECLARE num integer := 0;
BEGIN
IF ... THEN
SELECT COUNT(*) INTO num FROM ...
END IF;
IF num > 1 THEN
DELETE FROM ...
END IF;
RETURN NEW;
END;
As you can see my purpose is to count the rows returned by a query and perform some operation if it is greater than one.
Can this faulty code be responsible for the unwanted table created? If so, how to fix this?
SELECT ... INTO foo in PL/pgSQL stores the result of the SELECT in a PL/pgSQL variable foo. Whereas SELECT ... INTO foo run as an ordinary SQL statement creates a table foo to store the result.
This is what caused the confusion, the table was created when I was testing the SQL statements from the trigger function manually against the DB.

Why am I getting ORA-00904: invalid identifier for deterministic function index?

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).

SQL Oracle - Procedure Syntax (School assignment)

I'm currently learning SQL and I'm having trouble with a procedure of mine. The procedure should calculate the average of a column called 'INDICE_METABO_PAT'. The information I need is in 3-4 different tables. Then when I do have the average calculated, I update a table to set this average to the corresponding entries. Here is the procedure. Note that everything else in my .sql file works : inserts, updates, selects, views, etc.
create or replace Procedure SP_UPDATE_INDICE_METABO_DV (P_NO_ETUDE in number)
is
V_SOMME number := 0;
V_NBPATIENT number := 0;
V_NO_ETUDE number := P_NO_ETUDE;
cursor curseur is
select PATIENT.INDICE_EFFICACITE_METABO_PAT
from ETUDE, DROGUE_VARIANT, ETUDE_PATIENT, PATIENT
where ETUDE.NO_DROGUE = DROGUE_VARIANT.NO_DROGUE
and ETUDE.NO_VAR_GEN = DROGUE_VARIANT.NO_VAR_GEN
and V_NO_ETUDE = ETUDE_PATIENT.NO_ETUDE
and ETUDE_PATIENT.NO_PATIENT = PATIENT.NO_PATIENT;
begin
open curseur;
fetch curseur into V_SOMME;
V_NBPATIENT := V_NBPATIENT + 1;
exit when curseur%NOTFOUND;
update DROGUE_VARIANT
set INDICE_EFFICACITE_METABO_DV = V_SOMME / V_NBPATIENT
where exists(select * from ETUDE, DROGUE_VARIANT, ETUDE_PATIENT, PATIENT
where ETUDE.NO_DROGUE = DROGUE_VARIANT.NO_DROGUE
and ETUDE.NO_VAR_GEN = DROGUE_VARIANT.NO_VAR_GEN
and V_NO_ETUDE = ETUDE_PATIENT.NO_ETUDE
and ETUDE_PATIENT.NO_PATIENT = PATIENT.NO_PATIENT);
end SP_UPDATE_INDICE_METABO_DV;
/
I'm getting an error : Procedure compiled , error check compiler log.
But I can't open the compiler log, and when my friend opens it, it points to weird places, like my create tables and such.
This is school stuff by the way, so it'll be nice if you could give an insight instead of a direct solution. Thanks alot.
Thanks alot in advance for your kind help !
To see the error you can do show errors after your procedure creation statement, or you can query the user_errors or all_errors views.
That will show something like:
LINE/COL ERROR
-------- ------------------------------------------------------------------------
20/4 PLS-00376: illegal EXIT/CONTINUE statement; it must appear inside a loop
20/4 PL/SQL: Statement ignored
You mentioned that when you checked the complier log, which shows the same information, "it points to weird places". Presumably you're looking at line 20 in your script. But this message is referring to line 20 of the PL/SQL code block, which is the exit when curseur%NOTFOUND;, which makes sense for the error message.
And as the message also says, and as #ammoQ said in a comment, that should be in a loop. If you're trying to manually calculate the average in a procedure as an exercise, instead of using the built-in aggregation functions, then you need to loop over all of the rows from your cursor:
open curseur;
loop
fetch curseur into V_SOMME;
exit when curseur%NOTFOUND;
V_NBPATIENT := V_NBPATIENT + 1;
end loop;
close curseur;
But as you'll quickly realise, you'll end up with the v_somme variable having the last value retrieved, not the sum of all the values. You need a separate variable keep to track of the sum - fetch each value into a variable, and add that to your running total, all within the loop. But as requested, not giving a complete solution.
As you're starting out you should really use ANSI join syntax, not the old from/where syntax you have now. It's a shame that is still being taught. So your cursor query should be something like:
select PATIENT.INDICE_EFFICACITE_METABO_PAT
from ETUDE_PATIENT
join ETUDE
-- missing on clause !
join DROGUE_VARIANT
on DROGUE_VARIANT.NO_DROGUE = ETUDE.NO_DROGUE
and DROGUE_VARIANT.NO_VAR_GEN = ETUDE.NO_VAR_GEN
join PATIENT
on PATIENT.NO_PATIENT = ETUDE_PATIENT.NO_PATIENT
where ETUDE_PATIENT.NO_ETUDE = P_NO_ETUDE;
... which shows you that you are missing a join condition between ETUDE_PATIENT and ETUDE - it's unlikely you want a cartesian product, and it's much easier to spot that missing join using this syntax than with what you had.
You need to look at your update statement carefully too, particularly the exists clause. That will basically always return true if the cursor found anything, so it will update every row in DROGUE_VARIANT with your calculated average, which presumably isn't what you want.
There is no correlation between the rows in the table you're updating and the subquery in that clause - the DROGUE_VARIANT in the subquery is independent of the DROGUE_VARIANT you're updating. By which I mean, it's the same table, obviously; but the update and the subquery are looking at the table separately and so are looking at different rows. It also has the same missing join condition as the cursor query.

Oracle error : ORA-00905: Missing keyword

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.