Create a parameterless procedure - sql

I am trying to create a parameterless procedure that is used to take columns from a table and do some modifications to it and paste it into another table. But I am getting the following errors:
Procedure DEMO compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
4/2 PL/SQL: SQL Statement ignored
8/10 PLS-00403: expression 'NET.NETSALARY' cannot be used as an INTO-target of a SELECT/FETCH statement
8/24 PL/SQL: ORA-00904: : invalid identifier
Errors: check compiler log
My code used for this in sql is :
create or replace procedure "DEMO"
as
begin
case when comm is null then 0.9*grosssalary
when comm<500 then 0.85*grosssalary
else 0.8*grosssalary end
into net.netsalary from (select salary+comm as grossSalary,comm from
employee) ;
end ;
/
I am trying to insert the data into column netsalary of table net.
Please mention where did I go wrong?
Thanking you in advance.

Syntax is
CREATE OR REPLACE PROCEDURE demo
AS
BEGIN
INSERT INTO net (netsalary)
SELECT CASE
WHEN comm IS NULL THEN 0.9 * grosssalary
WHEN comm < 500 THEN 0.85 * grosssalary
ELSE 0.8 * grosssalary
END
FROM (SELECT salary + comm AS grossSalary, comm FROM employee);
END;
but it won't do much good. You're inserting as many rows as there are in the employee table, but ALL you insert is netsalary value - you don't even know who it belongs to.
Without knowing tables' description, it is difficult to guess what you really want to do.
insert? Probably employee number (or whatever that column name is) is missing
update? That's completely different command

Related

SQL command not ended properly at pkg_test

I have to write a stored procedure that starts copying the data from a table 'company' into a staging table 'company_stg' if no records for that date are present in it.
I have the following code :
CREATE OR REPLACE
PACKAGE BODY PKG_TEST AS
PROCEDURE SP_BILLING AS
BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM COMPANY INTO COMPANY_STG
WHERE NOT EXISTS (SELECT * FROM COMPANY_STG WHERE AS_OF_DATE = "2023-02-08")';
END;
END PKG_TEST;
I AM GETTING THE ERROR "SQL COMMAND NOT PROPERLY ENDED"
company * company_stg have as_of_date as a column. rest all are same.
please help me with this
I have also tried
if not exists (SELECT * FROM COMPANY_STG WHERE AS_OF_DATE = "2023-02-08")
then
select from company into company_stg
So many things look bad in that piece of code...
First, why use dynamic SQL execute immediate? It's best to avoid dynamic SQL as much as possible because it leads to runtime errors and requires pretty much instrumentation so that it may be debugged. Generally you use dynamic SQL when you do not know beforehand the name of a table it will operate on, which is not the case for you. You definitely know you have to work with tables COMPANY and COMPANY_STG. Is it not so?
Then, it doesn't look like you have read the manual to see an insert select.
When you insert into a table, it's best to give the list of columns into which you actually insert data. If one alters that table and adds one or more than one column, the insert which does not have the list of columns will crash.
Thus, to insert into COMPANY_STG data from COMPANY, the SQL should look like below:
insert into company_stg(
... ---- here should be the list of columns you insert data into
)
select
... --- here should the source columns you are willing to insert
from company c
where not exists (
select 1
from company_stg cs
where cs.as_of_date= --- what is the condition??? I did not understand
)
;
You have not given the structures for those tables, so that I can't give you the columns to select and to insert into. Nor did I really understand what the condition for inserting data should be.
SELECT does not perform a copy and SELECT * FROM COMPANY INTO COMPANY_STG is not valid syntax. You want to use an INSERT statement to do that (and check if there is any row first):
CREATE OR REPLACE PACKAGE BODY PKG_TEST AS
PROCEDURE SP_BILLING
AS
BEGIN
DECLARE
v_staged_count NUMBER;
BEGIN
SELECT 1
INTO v_staged_count
FROM COMPANY_STG
WHERE AS_OF_DATE = DATE '2023-02-08'
FETCH FIRST ROW ONLY; -- We don't care how many rows so stop after finding
-- the first one.
-- Stop as rows have been found.
RETURN;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Continue
NULL;
END;
INSERT INTO company_stg
SELECT *
FROM COMPANY;
END;
END PKG_TEST;
/
fiddle

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

Oracle PL/SQL - BEFORE INSERT 'table does not exist' error?

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.

Why is "ADD_YEARS" an invalid identifier?

I'm trying to use SQL's "ADD_YEARS" in an Oracle PLSQL Procedure.
However, (assuming it's actually to blame) it has an error on compilation: "invalid identifier".
I suspect that this is because the ADD_YEARS is something out of SQL, and not PLSQL. They don't seem to like each other. The only way I can think of doing this is to create a local variable and assign it the result I'd normally have gotten from ADD_YEARS. However, when I tried I couldn't figure out how to actually...assign some value to that. There's SELECT INTO but that makes 0 sense in this case.
-- If in good standing, extend membership 1 year.
-- If not but within grace (6 months), extend to 1 year from today.
-- Otherwise, explain renewal involves penalty. If no ID, print message.
CREATE OR REPLACE PROCEDURE renew(id1 IN member.id%type) IS
temp1 member.expr_date%type;
BEGIN
SELECT expr_date INTO temp1 FROM member WHERE id = id1;
IF temp1 > CURRENT_DATE THEN
UPDATE member
SET expr_date = ADD_YEARS(expr_date, 1)
WHERE id = id1;
ELSIF ADD_MONTHS(temp1, 6) > CURRENT_DATE THEN
UPDATE member
SET expr_date = ADD_YEARS(CURRENT_DATE, 1)
WHERE id = id1;
ELSE
dbms_output.put_line('Renewal will incur a penalty!');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('That ID does not exist as a member!');
END;
/
show errors
Here's the error I'm getting:
Errors for PROCEDURE RENEW:
LINE/COL ERROR
-------- -----------------------------------------------------------------
7/3 PL/SQL: SQL Statement ignored
8/19 PL/SQL: ORA-00904: "ADD_YEARS": invalid identifier
11/3 PL/SQL: SQL Statement ignored
12/19 PL/SQL: ORA-00904: "ADD_YEARS": invalid identifier
Thanks much for any help! I'm still very new to SQL and PL/SQL. Getting over some of its quirks has been difficult.
As mentioned in my comments, you cannot use ADD_YEARS since in Oracle nothing exist as ADD_YEARS. You can inturn use ADD_MONTHS or INTERVAL clause.
So you can modify your block update statement as :
SET expr_date = ADD_YEARS(expr_date, 1)
1) SET expr_date = ADD_MONTHS(expr_date, 12)
Or
2) SET expr_date = expr_date + interval '1' YEAR

PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ;

I am running the following script -
BEGIN
select department_name
from egpl_department
where department_id in (select department_id
from egpl_casemgmt_activity);
END ;
And got the Error -
PLS-00103: Encountered the symbol "end-of-file" when
expecting one of the following:
;
In a PL/SQL block select statement should have an into clause:
DECLARE
v_department egpl_department.department_name%type;
BEGIN
select department_name
into v_department
from egpl_department
where department_id in (select department_id from egpl_casemgmt_activity);
-- Do something useful with v_department
END;
PLS-00103 always means the compiler has hurled because we have made a syntax error. It would be really neat if the message text said: You have made a syntax error, please check your code but alas it doesn't.
Anyway, in this case the error is that in PL/SQL select statements must populate a variable. This is different from the behaviour of say T-SQL. So you need to define a variable which matches the projection of your query and select INTO that variable.
Oracle's documentation is comprehensive and online. You can find the section on integrating SQL queries into PL/SQL here. I urge you to read it, to forestall your next question. Because once you have fixed the simple syntax bloomer you're going to hit TOO_MANY_ROWS (assuming you have more than one department).
In PL/SQL you cannot just select some data. Where is the result supposed to go?
Your options are:
Remove BEGIN and END and run the SELECT with SQL*plus or some other tool that can run a SQL statement and present the result somewhere.
Use SELECT department_name INTO dep_name to put the result into a PL/SQL variable (only works if your SELECT returns a single row)
Use SELECT department_name BULK COLLECT INTO dep_name_table to put the result into a PL/SQL table (works for several rows)
Or maybe you can describe what you're trying to achieve and in what environment you want to run the SQL or PL/SQL code.
To avoid the too_many_rows problem, you could use a cursor, something like this (I haven't tested this, but along these lines )
DECLARE
v_department egpl_department.department_name%type;
cursor c_dept IS
select department_name
into v_department
from egpl_department
where department_id in (select department_id from egpl_casemgmt_activity)
order by department_name;
BEGIN
OPEN c_dept;
FETCH c_dept INTO v_department;
CLOSE c_dept;
-- do something with v_department
END;
This will put the first value it finds in the table into v_department. Use the ORDER BY clause to make sure the row returned would be the one you required, assuming there was the possibility of 2 different values.
Most people would not consider the call to be the issue,
but here's an amusing bug in Oracle Sql Developer that may emulate the issue..
exec dbowner.sp1 ( p1, p2, p3); -- notes about the fields
Error report -
ORA-06550: line 1, column 362:
PLS-00103: Encountered the symbol "end-of-file" 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
<< close current delete fetch lock insert
open rollback savepoint set sql execute commit forall merge
pipe
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
exec dbowner.sp1 ( p1, p2, p3);
-- notes about the fields
PL/SQL procedure successfully completed.
DECLARE is only used in anonymous PL/SQL blocks and nested PL/SQL blocks.
You do not need to use the DECLARE key word before you 'introduce' a new variable in a Procedure block, unless .... the procedure is a nested PL/SQL block.
This is an example of how you would declare a variable without the 'DECLARE' Key word below.
eg.;
CREATE OR REPLACE PROCEDURE EXAMPLE( A IN NUMBER, B OUT VARCHAR2 )
IS
num1 number;
BEGIN
num1:=1;
insert into a (year) values(7);
END;
This question/answer explains it better
create procedure in oracle